[pypy-svn] pypy default: hg merge post-release-1.5

arigo commits-noreply at bitbucket.org
Sat Apr 30 18:05:09 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r43817:ea4e1fd5b529
Date: 2011-04-30 18:03 +0200
http://bitbucket.org/pypy/pypy/changeset/ea4e1fd5b529/

Log:	hg merge post-release-1.5

diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py
--- a/pypy/translator/c/node.py
+++ b/pypy/translator/c/node.py
@@ -11,7 +11,7 @@
 from pypy.translator.c.support import c_char_array_constant, barebonearray
 from pypy.translator.c.primitive import PrimitiveType, name_signed
 from pypy.rlib import exports
-from pypy.rlib.rfloat import isinf, isnan
+from pypy.rlib.rfloat import isfinite
 from pypy.rlib.rstackovf import _StackOverflow
 from pypy.translator.c import extfunc
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -793,7 +793,7 @@
             node = db.getcontainernode(value._obj)
             expr = 'NULL /*%s*/' % node.name
             node.where_to_copy_me.append('&%s' % access_expr)
-        elif typeOf(value) == Float and (isinf(value) or isnan(value)):
+        elif typeOf(value) == Float and not isfinite(value):
             db.late_initializations.append(('%s' % access_expr, db.get(value)))
             expr = '0.0 /* patched later by %sinfinity */' % (
                 '-+'[value > 0])

diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py
--- a/pypy/translator/c/test/test_genc.py
+++ b/pypy/translator/c/test/test_genc.py
@@ -273,7 +273,7 @@
     assert res == 1.5
 
 def test_nan_and_special_values():
-    from pypy.rlib.rfloat import isnan, isinf, copysign
+    from pypy.rlib.rfloat import isnan, isinf, isfinite, copysign
     inf = 1e300 * 1e300
     assert isinf(inf)
     nan = inf/inf
@@ -283,6 +283,7 @@
             (inf,   lambda x: isinf(x) and x > 0.0),
             (-inf,  lambda x: isinf(x) and x < 0.0),
             (nan,   isnan),
+            (42.0,  isfinite),
             (0.0,   lambda x: not x and copysign(1., x) == 1.),
             (-0.0,  lambda x: not x and copysign(1., x) == -1.),
             ]:

diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -158,12 +158,12 @@
         return _formatd(x, code, precision, flags)
 
 def double_to_string(value, tp, precision, flags):
-    if isnan(value):
-        special = DIST_NAN
+    if isfinite(value):
+        special = DIST_FINITE
     elif isinf(value):
         special = DIST_INFINITY
-    else:
-        special = DIST_FINITE
+    else:  #isnan(value):
+        special = DIST_NAN
     result = formatd(value, tp, precision, flags)
     return result, special
 
@@ -344,7 +344,7 @@
     def asinh(x):
         "NOT_RPYTHON"
         absx = abs(x)
-        if isnan(x) or isinf(x):
+        if not isfinite(x):
             return x
         if absx < _2_to_m28:
             return x
@@ -405,3 +405,6 @@
         r = math.floor(absx)
     return copysign(r, x)
 
+def isfinite(x):
+    "NOT_RPYTHON"
+    return not isinf(x) and not isnan(x)

diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -617,7 +617,7 @@
 
     if w_obj.is_cpytype():
         Py_DecRef(space, pto.c_tp_dict)
-        w_dict = space.newdict(from_strdict_shared=w_obj.dict_w)
+        w_dict = w_obj.getdict(space)
         pto.c_tp_dict = make_ref(space, w_dict)
 
 @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)

diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2118,6 +2118,45 @@
         res = self.interp_operations(f, [])
         assert res
 
+    def test_bug688_multiple_immutable_fields(self):
+        myjitdriver = JitDriver(greens=[], reds=['counter','context'])
+
+        class Tag:
+            pass
+        class InnerContext():
+            _immutable_fields_ = ['variables','local_names']
+            def __init__(self, variables):
+                self.variables = variables
+                self.local_names = [0]
+
+            def store(self):
+                self.local_names[0] = 1
+
+            def retrieve(self):
+                variables = hint(self.variables, promote=True)
+                result = self.local_names[0]
+                if result == 0:
+                    return -1
+                else:
+                    return -1
+        def build():
+            context = InnerContext(Tag())
+
+            context.store()
+
+            counter = 0
+            while True:
+                myjitdriver.jit_merge_point(context=context, counter = counter)
+                context.retrieve()
+                context.retrieve()
+
+                counter += 1
+                if counter > 10:
+                    return 7
+        assert self.meta_interp(build, []) == 7
+        self.check_loops(getfield_gc_pure=0)
+        self.check_loops(getfield_gc_pure=2, everywhere=True)
+        
 class TestOOtype(BasicTests, OOJitMixin):
 
     def test_oohash(self):

diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -34,13 +34,7 @@
     @staticmethod
     def allocate_and_init_instance(space, w_type=None, module=False,
                                    instance=False, classofinstance=None,
-                                   from_strdict_shared=None, strdict=False):
-        if from_strdict_shared is not None:
-            assert w_type is None
-            assert not module and not instance and classofinstance is None
-            w_self = StrDictImplementation(space)
-            w_self.content = from_strdict_shared
-            return w_self
+                                   strdict=False):
         if space.config.objspace.std.withcelldict and module:
             from pypy.objspace.std.celldict import ModuleDictImplementation
             assert w_type is None

diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
--- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
@@ -1086,6 +1086,50 @@
             --TICK--
             jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=<Loop0>)
         """)
+        
+    def test_mutate_class(self):
+        def fn(n):
+            class A(object):
+                count = 1
+                def __init__(self, a):
+                    self.a = a
+                def f(self):
+                    return self.count
+            i = 0
+            a = A(1)
+            while i < n:
+                A.count += 1 # ID: mutate
+                i = a.f()    # ID: meth1
+            return i
+        #
+        log = self.run(fn, [1000], threshold=10)
+        assert log.result == 1000
+        #
+        # first, we test the entry bridge
+        # -------------------------------
+        entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True)
+        ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR')
+        assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value',
+                                    'getfield_gc', 'guard_nonnull_class']
+        # the STORE_ATTR is folded away
+        assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == []
+        #
+        # then, the actual loop
+        # ----------------------
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i8 = getfield_gc_pure(p5, descr=<SignedFieldDescr .*W_IntObject.inst_intval.*>)
+            i9 = int_lt(i8, i7)
+            guard_true(i9, descr=.*)
+            i11 = int_add(i8, 1)
+            i12 = force_token()
+            --TICK--
+            p20 = new_with_vtable(ConstClass(W_IntObject))
+            setfield_gc(p20, i11, descr=<SignedFieldDescr.*W_IntObject.inst_intval .*>)
+            setfield_gc(ConstPtr(ptr21), p20, descr=<GcPtrFieldDescr .*TypeCell.inst_w_value .*>)
+            jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=<Loop.>)
+        """)
+
 
     def test_intbound_simple(self):
         """

diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py
--- a/lib-python/modified-2.7/test/test_descr.py
+++ b/lib-python/modified-2.7/test/test_descr.py
@@ -3190,7 +3190,8 @@
             except TypeError:
                 pass
             else:
-                self.fail("%r's __dict__ can be modified" % cls)
+                if test_support.check_impl_detail(pypy=False):
+                    self.fail("%r's __dict__ can be modified" % cls)
 
         # Modules also disallow __dict__ assignment
         class Module1(types.ModuleType, Base):

diff --git a/pypy/jit/metainterp/optimizeutil.py b/pypy/jit/metainterp/optimizeutil.py
--- a/pypy/jit/metainterp/optimizeutil.py
+++ b/pypy/jit/metainterp/optimizeutil.py
@@ -99,7 +99,9 @@
     make_sure_not_resized(args)
     res = 0x345678
     for arg in args:
-        if isinstance(arg, history.Const):
+        if arg is None:
+            y = 17
+        elif isinstance(arg, history.Const):
             y = arg._get_hash_()
         else:
             y = compute_identity_hash(arg)

diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py
--- a/pypy/rpython/test/test_rfloat.py
+++ b/pypy/rpython/test/test_rfloat.py
@@ -157,9 +157,9 @@
         self.interpret(fn, [1.0, 2.0, 3.0])
 
     def test_copysign(self):
-        import math
+        from pypy.rlib import rfloat
         def fn(x, y):
-            return math.copysign(x, y)
+            return rfloat.copysign(x, y)
         assert self.interpret(fn, [42, -1]) == -42
         assert self.interpret(fn, [42, -0.0]) == -42
         assert self.interpret(fn, [42, 0.0]) == 42
@@ -172,21 +172,42 @@
         assert self.interpret(fn, [0]) == 42.3
 
     def test_isnan(self):
-        import math
-        def fn(x):
-            inf = x * x
-            nan = inf / inf
-            return math.isnan(nan)
-        assert self.interpret(fn, [1e200])
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isnan(n1 / n2)
+        assert self.interpret(fn, [1e200, 1e200])   # nan
+        assert not self.interpret(fn, [1e200, 1.0])   # +inf
+        assert not self.interpret(fn, [1e200, -1.0])  # -inf
+        assert not self.interpret(fn, [42.5, 2.3])    # +finite
+        assert not self.interpret(fn, [42.5, -2.3])   # -finite
 
     def test_isinf(self):
-        import math
-        def fn(x):
-            inf = x * x
-            return math.isinf(inf)
-        assert self.interpret(fn, [1e200])
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isinf(n1 / n2)
+        assert self.interpret(fn, [1e200, 1.0])       # +inf
+        assert self.interpret(fn, [1e200, -1.0])      # -inf
+        assert not self.interpret(fn, [1e200, 1e200]) # nan
+        assert not self.interpret(fn, [42.5, 2.3])    # +finite
+        assert not self.interpret(fn, [42.5, -2.3])   # -finite
 
-        
+    def test_isfinite(self):
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isfinite(n1 / n2)
+        assert self.interpret(fn, [42.5, 2.3])        # +finite
+        assert self.interpret(fn, [42.5, -2.3])       # -finite
+        assert not self.interpret(fn, [1e200, 1.0])   # +inf
+        assert not self.interpret(fn, [1e200, -1.0])  # -inf
+        assert not self.interpret(fn, [1e200, 1e200]) # nan
+
+
 class TestLLtype(BaseTestRfloat, LLRtypeMixin):
 
     def test_hash(self):

diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -220,7 +220,7 @@
         self.optimizer.pure_operations[self.optimizer.make_args_key(op)] = op
 
     def has_pure_result(self, opnum, args, descr):
-        op = ResOperation(opnum, args, None)
+        op = ResOperation(opnum, args, None, descr)
         key = self.optimizer.make_args_key(op)
         op = self.optimizer.pure_operations.get(key, None)
         if op is None:
@@ -482,7 +482,7 @@
 
     def make_args_key(self, op):
         n = op.numargs()
-        args = [None] * (n + 1)
+        args = [None] * (n + 2)
         for i in range(n):
             arg = op.getarg(i)
             try:
@@ -493,6 +493,7 @@
                 arg = value.get_key_box()
             args[i] = arg
         args[n] = ConstInt(op.getopnum())
+        args[n+1] = op.getdescr()
         return args
 
     def optimize_default(self, op):


diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -101,14 +101,20 @@
 # Custom implementations
 
 def ll_math_isnan(y):
-    # By not calling into the extenal function the JIT can inline this.  Floats
-    # are awesome.
+    # By not calling into the external function the JIT can inline this.
+    # Floats are awesome.
     return y != y
 
 def ll_math_isinf(y):
     # Use a bitwise OR so the JIT doesn't produce 2 different guards.
     return (y == INFINITY) | (y == -INFINITY)
 
+def ll_math_isfinite(y):
+    # Use a custom hack that is reasonably well-suited to the JIT.
+    # Floats are awesome (bis).
+    z = 0.0 * y
+    return z == z       # i.e.: z is not a NaN
+
 
 ll_math_floor = math_floor
 

diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -54,7 +54,6 @@
             from pypy.objspace.std.slicetype  import slice_typedef
             from pypy.objspace.std.longtype   import long_typedef
             from pypy.objspace.std.unicodetype import unicode_typedef
-            from pypy.objspace.std.dictproxytype import dictproxy_typedef
             from pypy.objspace.std.nonetype import none_typedef
             from pypy.objspace.std.itertype import iter_typedef
         self.pythontypes = [value for key, value in result.__dict__.items()
@@ -123,7 +122,6 @@
             iterobject.W_FastTupleIterObject: [],
             iterobject.W_ReverseSeqIterObject: [],
             unicodeobject.W_UnicodeObject: [],
-            dictproxyobject.W_DictProxyObject: [],
             dictmultiobject.W_DictViewKeysObject: [],
             dictmultiobject.W_DictViewItemsObject: [],
             dictmultiobject.W_DictViewValuesObject: [],

diff --git a/pypy/objspace/std/test/test_dictproxy.py b/pypy/objspace/std/test/test_dictproxy.py
--- a/pypy/objspace/std/test/test_dictproxy.py
+++ b/pypy/objspace/std/test/test_dictproxy.py
@@ -1,21 +1,26 @@
-
+from pypy.conftest import gettestobjspace
 
 class AppTestUserObject:
     def test_dictproxy(self):
         class NotEmpty(object):
             a = 1
-        assert isinstance(NotEmpty.__dict__, dict) == False
+        NotEmpty.a = 1
+        NotEmpty.a = 1
+        NotEmpty.a = 1
+        NotEmpty.a = 1
         assert 'a' in NotEmpty.__dict__
         assert 'a' in NotEmpty.__dict__.keys()
         assert 'b' not in NotEmpty.__dict__
-        assert isinstance(NotEmpty.__dict__.copy(), dict)
-        assert NotEmpty.__dict__ == NotEmpty.__dict__.copy()
-        try:
-            NotEmpty.__dict__['b'] = 1
-        except:
-            pass
-        else:
-            raise AssertionError, 'this should not have been writable'
+        NotEmpty.__dict__['b'] = 4
+        assert NotEmpty.b == 4
+        del NotEmpty.__dict__['b']
+        assert NotEmpty.__dict__.get("b") is None
+        raises(TypeError, 'NotEmpty.__dict__[15] = "y"')
+        raises(KeyError, 'del NotEmpty.__dict__[15]')
+        assert NotEmpty.__dict__.setdefault("string", 1) == 1
+        assert NotEmpty.__dict__.setdefault("string", 2) == 1
+        assert NotEmpty.string == 1
+        raises(TypeError, 'NotEmpty.__dict__.setdefault(15, 1)')
 
     def test_dictproxyeq(self):
         class a(object):
@@ -33,7 +38,13 @@
     def test_str_repr(self):
         class a(object):
             pass
-        s = repr(a.__dict__)
-        assert s.startswith('<dictproxy') and s.endswith('>')
-        s = str(a.__dict__)
-        assert s.startswith('{') and s.endswith('}')
+        s1 = repr(a.__dict__)
+        s2 = str(a.__dict__)
+        assert s1 == s2
+        assert s1.startswith('{') and s1.endswith('}')
+
+class AppTestUserObjectMethodCache(AppTestUserObject):
+    def setup_class(cls):
+        cls.space = gettestobjspace(
+            **{"objspace.std.withmethodcachecounter": True})
+

diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py
--- a/pypy/objspace/std/test/test_setobject.py
+++ b/pypy/objspace/std/test/test_setobject.py
@@ -284,6 +284,18 @@
         # All empty frozenset subclass instances should have different ids
         assert len(set(map(id, efs))) == len(efs)
 
+    def test_subclass_union(self):
+        for base in [set, frozenset]:
+            class subset(base):
+                def __init__(self, *args):
+                    self.x = args
+            s = subset([2])
+            assert s.x == ([2],)
+            t = s | base([5])
+            # obscure CPython behavior:
+            assert type(t) is subset
+            assert not hasattr(t, 'x')
+
     def test_isdisjoint(self):
         assert set([1,2,3]).isdisjoint(set([4,5,6]))
         assert set([1,2,3]).isdisjoint(frozenset([4,5,6]))

diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -787,12 +787,10 @@
     def newtuple(self, l):
         return tuple(l)
 
-    def newdict(self, module=False, instance=False, classofinstance=None,
-                from_strdict_shared=None):
+    def newdict(self, module=False, instance=False, classofinstance=None):
         return W_DictMultiObject.allocate_and_init_instance(
                 self, module=module, instance=instance,
-                classofinstance=classofinstance,
-                from_strdict_shared=from_strdict_shared)
+                classofinstance=classofinstance)
 
     def finditem_str(self, w_dict, s):
         return w_dict.getitem_str(s) # assume it's a multidict

diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -408,6 +408,13 @@
     guard_op = old_loop.operations[old_index]
     assert guard_op.is_guard()
     guard_op.jump_target = new_loop
+    # check that the bridge's inputargs are of the correct number and
+    # kind for the guard
+    if guard_op.fail_args is not None:
+        argkinds = [v.concretetype for v in guard_op.fail_args if v]
+    else:
+        argkinds = []
+    assert argkinds == [v.concretetype for v in new_loop.inputargs]
 
 # ------------------------------
 

diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py
--- a/pypy/objspace/std/dictproxyobject.py
+++ b/pypy/objspace/std/dictproxyobject.py
@@ -1,15 +1,88 @@
 from pypy.objspace.std.model import registerimplementation, W_Object
 from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation
+from pypy.objspace.std.typeobject import unwrap_cell
+from pypy.interpreter.error import OperationError
 
-def descr_get_dictproxy(space, w_obj):
-    return W_DictProxyObject(w_obj.getdict(space))
 
-class W_DictProxyObject(W_Object):
-    from pypy.objspace.std.dictproxytype import dictproxy_typedef as typedef
+class W_DictProxyObject(W_DictMultiObject):
+    def __init__(w_self, space, w_type):
+        W_DictMultiObject.__init__(w_self, space)
+        w_self.w_type = w_type
 
-    def __init__(w_self, w_dict):
-        w_self.w_dict = w_dict
+    def impl_getitem(self, w_lookup):
+        space = self.space
+        w_lookup_type = space.type(w_lookup)
+        if space.is_w(w_lookup_type, space.w_str):
+            return self.impl_getitem_str(space.str_w(w_lookup))
+        else:
+            return None
 
-registerimplementation(W_DictProxyObject)
+    def impl_getitem_str(self, lookup):
+        return self.w_type.getdictvalue(self.space, lookup)
 
-register_all(vars())
+    def impl_setitem(self, w_key, w_value):
+        space = self.space
+        if space.is_w(space.type(w_key), space.w_str):
+            self.impl_setitem_str(self.space.str_w(w_key), w_value)
+        else:
+            raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type"))
+
+    def impl_setitem_str(self, name, w_value):
+        self.w_type.setdictvalue(self.space, name, w_value)
+
+    def impl_setdefault(self, w_key, w_default):
+        space = self.space
+        w_result = self.impl_getitem(w_key)
+        if w_result is not None:
+            return w_result
+        self.impl_setitem(w_key, w_default)
+        return w_default
+
+    def impl_delitem(self, w_key):
+        space = self.space
+        w_key_type = space.type(w_key)
+        if space.is_w(w_key_type, space.w_str):
+            if not self.w_type.deldictvalue(space, w_key):
+                raise KeyError
+        else:
+            raise KeyError
+
+    def impl_length(self):
+        return len(self.w_type.dict_w)
+
+    def impl_iter(self):
+        return DictProxyIteratorImplementation(self.space, self)
+
+    def impl_keys(self):
+        space = self.space
+        return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()]
+
+    def impl_values(self):
+        return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()]
+
+    def impl_items(self):
+        space = self.space
+        return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)])
+                    for (key, w_value) in self.w_type.dict_w.iteritems()]
+
+    def impl_clear(self):
+        self.w_type.dict_w.clear()
+        self.w_type.mutated()
+
+    def _as_rdict(self):
+        assert 0, "should be unreachable"
+
+    def _clear_fields(self):
+        assert 0, "should be unreachable"
+
+class DictProxyIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, dictimplementation):
+        IteratorImplementation.__init__(self, space, dictimplementation)
+        self.iterator = dictimplementation.w_type.dict_w.iteritems()
+
+    def next_entry(self):
+        for key, w_value in self.iterator:
+            return (self.space.wrap(key), unwrap_cell(self.space, w_value))
+        else:
+            return (None, None)

diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -310,7 +310,7 @@
 
 def ne__Set_settypedef(space, w_left, w_other):
     rd = make_setdata_from_w_iterable(space, w_other)
-    return space.wrap(_is_eq(w_left.setdata, rd))
+    return space.wrap(not _is_eq(w_left.setdata, rd))
 
 ne__Set_frozensettypedef = ne__Set_settypedef
 ne__Frozenset_settypedef = ne__Set_settypedef

diff --git a/pypy/objspace/std/dictproxytype.py b/pypy/objspace/std/dictproxytype.py
deleted file mode 100644
--- a/pypy/objspace/std/dictproxytype.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from pypy.interpreter import gateway
-from pypy.interpreter.typedef import GetSetProperty
-from pypy.interpreter.error import OperationError
-from pypy.objspace.std.stdtypedef import StdTypeDef
-
-# ____________________________________________________________
-
-def _proxymethod(name):
-    def fget(space, w_obj):
-        from pypy.objspace.std.dictproxyobject import W_DictProxyObject
-        if not isinstance(w_obj, W_DictProxyObject):
-            raise OperationError(space.w_TypeError,
-                                 space.wrap("expected dictproxy"))
-        return space.getattr(w_obj.w_dict, space.wrap(name))
-    return GetSetProperty(fget)
-
-def _compareproxymethod(opname):
-    def compare(space, w_obj1, w_obj2):
-        from pypy.objspace.std.dictproxyobject import W_DictProxyObject
-        if not isinstance(w_obj1, W_DictProxyObject):
-            raise OperationError(space.w_TypeError,
-                                 space.wrap("expected dictproxy"))
-        return getattr(space, opname)(w_obj1.w_dict, w_obj2)
-    compare.func_name = "dictproxy_compare_%s" % (opname, )
-    return gateway.interp2app(compare)
-
-# ____________________________________________________________
-
-dictproxy_typedef = StdTypeDef("dictproxy",
-    has_key = _proxymethod('has_key'),
-    get = _proxymethod('get'),
-    keys = _proxymethod('keys'),
-    values = _proxymethod('values'),
-    items = _proxymethod('items'),
-    iterkeys = _proxymethod('iterkeys'),
-    itervalues = _proxymethod('itervalues'),
-    iteritems = _proxymethod('iteritems'),
-    copy = _proxymethod('copy'),
-    __len__ = _proxymethod('__len__'),
-    __getitem__ = _proxymethod('__getitem__'),
-    __contains__ = _proxymethod('__contains__'),
-    __str__ = _proxymethod('__str__'),
-    __iter__ = _proxymethod('__iter__'),
-    __lt__ = _compareproxymethod('lt'),
-    __le__ = _compareproxymethod('le'),
-    __eq__ = _compareproxymethod('eq'),
-    __ne__ = _compareproxymethod('ne'),
-    __gt__ = _compareproxymethod('gt'),
-    __ge__ = _compareproxymethod('ge'),
-)
-dictproxy_typedef.registermethods(globals())

diff --git a/pypy/objspace/std/test/test_versionedtype.py b/pypy/objspace/std/test/test_versionedtype.py
--- a/pypy/objspace/std/test/test_versionedtype.py
+++ b/pypy/objspace/std/test/test_versionedtype.py
@@ -189,6 +189,30 @@
         assert btag is atag
         assert btag is not None
 
+    def test_version_tag_when_changing_a_lot(self):
+        space = self.space
+        w_x = space.wrap("x")
+        w_A, w_B, w_C = self.get_three_classes()
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(1))
+        assert w_A.version_tag() is not atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 1
+
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(2))
+        assert w_A.version_tag() is not atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 2
+
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(3))
+        assert w_A.version_tag() is atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 3
+
+        space.setattr(w_A, w_x, space.newint(4))
+        assert w_A.version_tag() is atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 4
+
+
 class AppTestVersionedType(test_typeobject.AppTestTypeObject):
     def setup_class(cls):
         cls.space = gettestobjspace(**{"objspace.std.withtypeversion": True})

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -1,7 +1,7 @@
 from pypy.rlib.rarithmetic import LONG_BIT, intmask, r_uint, r_ulonglong
 from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen
 from pypy.rlib.rarithmetic import most_neg_value_of_same_type
-from pypy.rlib.rfloat import isinf, isnan
+from pypy.rlib.rfloat import isfinite
 from pypy.rlib.debug import make_sure_not_resized, check_regular_int
 from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.rlib import jit
@@ -173,9 +173,15 @@
     def fromfloat(dval):
         """ Create a new bigint object from a float """
         # This function is not marked as pure because it can raise
+        if isfinite(dval):
+            return rbigint._fromfloat_finite(dval)
+        else:
+            raise OverflowError
+
+    @staticmethod
+    @jit.purefunction
+    def _fromfloat_finite(dval):
         sign = 1
-        if isinf(dval) or isnan(dval):
-            raise OverflowError
         if dval < 0.0:
             sign = -1
             dval = -dval

diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -4,15 +4,25 @@
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.typedef import weakref_descr
+from pypy.interpreter.baseobjspace import W_Root
 from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member
 from pypy.objspace.std.objecttype import object_typedef
-from pypy.objspace.std.dictproxyobject import W_DictProxyObject
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash
 from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted
 from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe
 from pypy.rlib.rarithmetic import intmask, r_uint
 
+class TypeCell(W_Root):
+    def __init__(self, w_value=None):
+        self.w_value = w_value
+
+def unwrap_cell(space, w_value):
+    if (space.config.objspace.std.withtypeversion and
+            isinstance(w_value, TypeCell)):
+        return w_value.w_value
+    return w_value
+
 # from compiler/misc.py
 
 MANGLE_LEN = 256 # magic constant from compile.c
@@ -211,6 +221,17 @@
         return compute_C3_mro(w_self.space, w_self)
 
     def getdictvalue(w_self, space, attr):
+        if space.config.objspace.std.withtypeversion:
+            version_tag = w_self.version_tag()
+            if version_tag is not None:
+                return unwrap_cell(
+                    space,
+                    w_self._pure_getdictvalue_no_unwrapping(
+                        space, version_tag, attr))
+        w_value = w_self._getdictvalue_no_unwrapping(space, attr)
+        return unwrap_cell(space, w_value)
+
+    def _getdictvalue_no_unwrapping(w_self, space, attr):
         w_value = w_self.dict_w.get(attr, None)
         if w_self.lazyloaders and w_value is None:
             if attr in w_self.lazyloaders:
@@ -225,6 +246,48 @@
                     return w_value
         return w_value
 
+    @purefunction
+    def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr):
+        return w_self._getdictvalue_no_unwrapping(space, attr)
+
+    def setdictvalue(w_self, space, name, w_value):
+        if (not space.config.objspace.std.mutable_builtintypes
+                and not w_self.is_heaptype()):
+            msg = "can't set attributes on type object '%s'"
+            raise operationerrfmt(space.w_TypeError, msg, w_self.name)
+        if name == "__del__" and name not in w_self.dict_w:
+            msg = "a __del__ method added to an existing type will not be called"
+            space.warn(msg, space.w_RuntimeWarning)
+        if space.config.objspace.std.withtypeversion:
+            version_tag = w_self.version_tag()
+            if version_tag is not None:
+                w_curr = w_self._pure_getdictvalue_no_unwrapping(
+                        space, version_tag, name)
+                if w_curr is not None:
+                    if isinstance(w_curr, TypeCell):
+                        w_curr.w_value = w_value
+                        return True
+                    w_value = TypeCell(w_value)
+        w_self.mutated()
+        w_self.dict_w[name] = w_value
+        return True
+
+    def deldictvalue(w_self, space, w_key):
+        if w_self.lazyloaders:
+            w_self._freeze_()    # force un-lazification
+        key = space.str_w(w_key)
+        if (not space.config.objspace.std.mutable_builtintypes
+                and not w_self.is_heaptype()):
+            msg = "can't delete attributes on type object '%s'"
+            raise operationerrfmt(space.w_TypeError, msg, w_self.name)
+        try:
+            del w_self.dict_w[key]
+        except KeyError:
+            return False
+        else:
+            w_self.mutated()
+            return True
+
     def lookup(w_self, name):
         # note that this doesn't call __get__ on the result at all
         space = w_self.space
@@ -280,7 +343,7 @@
         space = w_self.space
         for w_class in w_self.mro_w:
             assert isinstance(w_class, W_TypeObject)
-            w_value = w_class.getdictvalue(space, key)
+            w_value = w_class._getdictvalue_no_unwrapping(space, key)
             if w_value is not None:
                 return w_class, w_value
         return None, None
@@ -293,7 +356,8 @@
         if version_tag is None:
             tup = w_self._lookup_where(name)
             return tup
-        return w_self._pure_lookup_where_with_method_cache(name, version_tag)
+        w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag)
+        return w_class, unwrap_cell(space, w_value)
 
     @purefunction
     def _pure_lookup_where_with_method_cache(w_self, name, version_tag):
@@ -358,10 +422,10 @@
         return False
 
     def getdict(w_self, space): # returning a dict-proxy!
+        from pypy.objspace.std.dictproxyobject import W_DictProxyObject
         if w_self.lazyloaders:
             w_self._freeze_()    # force un-lazification
-        newdic = space.newdict(from_strdict_shared=w_self.dict_w)
-        return W_DictProxyObject(newdic)
+        return W_DictProxyObject(space, w_self)
 
     def unwrap(w_self, space):
         if w_self.instancetypedef.fakedcpytype is not None:
@@ -395,15 +459,15 @@
     def get_module(w_self):
         space = w_self.space
         if w_self.is_heaptype() and '__module__' in w_self.dict_w:
-            return w_self.dict_w['__module__']
+            return w_self.getdictvalue(space, '__module__')
         else:
             # for non-heap types, CPython checks for a module.name in the
             # type name.  That's a hack, so we're allowed to use a different
             # hack...
             if ('__module__' in w_self.dict_w and
-                space.is_true(space.isinstance(w_self.dict_w['__module__'],
+                space.is_true(space.isinstance(w_self.getdictvalue(space, '__module__'),
                                                space.w_str))):
-                return w_self.dict_w['__module__']
+                return w_self.getdictvalue(space, '__module__')
             return space.wrap('__builtin__')
 
     def get_module_type_name(w_self):
@@ -800,52 +864,9 @@
                           "type object '%s' has no attribute '%s'",
                           w_type.name, name)
 
-def setattr__Type_ANY_ANY(space, w_type, w_name, w_value):
-    # Note. This is exactly the same thing as descroperation.descr__setattr__,
-    # but it is needed at bootstrap to avoid a call to w_type.getdict() which
-    # would un-lazify the whole type.
-    name = space.str_w(w_name)
-    w_descr = space.lookup(w_type, name)
-    if w_descr is not None:
-        if space.is_data_descr(w_descr):
-            space.set(w_descr, w_type, w_value)
-            return
-    
-    if (not space.config.objspace.std.mutable_builtintypes
-            and not w_type.is_heaptype()):
-        msg = "can't set attributes on type object '%s'"
-        raise operationerrfmt(space.w_TypeError, msg, w_type.name)
-    if name == "__del__" and name not in w_type.dict_w:
-        msg = "a __del__ method added to an existing type will not be called"
-        space.warn(msg, space.w_RuntimeWarning)
-    w_type.mutated()
-    w_type.dict_w[name] = w_value
-
 def eq__Type_Type(space, w_self, w_other):
     return space.is_(w_self, w_other)
 
-def delattr__Type_ANY(space, w_type, w_name):
-    if w_type.lazyloaders:
-        w_type._freeze_()    # force un-lazification
-    name = space.str_w(w_name)
-    w_descr = space.lookup(w_type, name)
-    if w_descr is not None:
-        if space.is_data_descr(w_descr):
-            space.delete(w_descr, w_type)
-            return
-    if (not space.config.objspace.std.mutable_builtintypes
-            and not w_type.is_heaptype()):
-        msg = "can't delete attributes on type object '%s'"
-        raise operationerrfmt(space.w_TypeError, msg, w_type.name)
-    try:
-        del w_type.dict_w[name]
-    except KeyError:
-        raise OperationError(space.w_AttributeError, w_name)
-    else:
-        w_type.mutated()
-        return
-
-
 # ____________________________________________________________
 
 

diff --git a/pypy/objspace/std/test/test_methodcache.py b/pypy/objspace/std/test/test_methodcache.py
--- a/pypy/objspace/std/test/test_methodcache.py
+++ b/pypy/objspace/std/test/test_methodcache.py
@@ -65,7 +65,7 @@
         cache_counter = __pypy__.method_cache_counter("f")
         # the cache hits come from A.f = ..., which first does a lookup on A as
         # well
-        assert cache_counter == (9, 11)
+        assert cache_counter == (17, 3)
 
     def test_subclasses(self):
         import __pypy__
@@ -148,3 +148,32 @@
         assert cache_counter[0] >= 5
         assert cache_counter[1] >= 1 # should be (27, 3)
         assert sum(cache_counter) == 10
+
+    def test_mutate_class(self):
+        import __pypy__
+        class A(object):
+            x = 1
+            y = 2
+        __pypy__.reset_method_cache_counter()
+        a = A()
+        for i in range(100):
+            assert a.y == 2
+            assert a.x == i + 1
+            A.x += 1
+        cache_counter = __pypy__.method_cache_counter("x")
+        assert cache_counter[0] >= 350
+        assert cache_counter[1] >= 1
+        assert sum(cache_counter) == 400
+
+        __pypy__.reset_method_cache_counter()
+        a = A()
+        for i in range(100):
+            assert a.y == 2
+            setattr(a, "a%s" % i, i)
+        cache_counter = __pypy__.method_cache_counter("x")
+        assert cache_counter[0] == 0 # 0 hits, because all the attributes are new
+
+    def test_get_module_from_namedtuple(self):
+        # this used to crash
+        from collections import namedtuple
+        assert namedtuple("a", "b").__module__

diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py
--- a/pypy/objspace/std/typetype.py
+++ b/pypy/objspace/std/typetype.py
@@ -207,38 +207,28 @@
 
 def descr_set__module(space, w_type, w_value):
     w_type = _check(space, w_type)
-    if not w_type.is_heaptype():
-        raise operationerrfmt(space.w_TypeError,
-                              "can't set %s.__module__",
-                              w_type.name)
-    w_type.mutated()
-    w_type.dict_w['__module__'] = w_value
+    w_type.setdictvalue(space, '__module__', w_value)
 
 def descr_get___abstractmethods__(space, w_type):
     w_type = _check(space, w_type)
     # type itself has an __abstractmethods__ descriptor (this). Don't return it
     if not space.is_w(w_type, space.w_type):
-        try:
-            return w_type.dict_w["__abstractmethods__"]
-        except KeyError:
-            pass
+        w_result = w_type.getdictvalue(space, "__abstractmethods__")
+        if w_result is not None:
+            return w_result
     raise OperationError(space.w_AttributeError,
                          space.wrap("__abstractmethods__"))
 
 def descr_set___abstractmethods__(space, w_type, w_new):
     w_type = _check(space, w_type)
-    w_type.dict_w["__abstractmethods__"] = w_new
-    w_type.mutated()
+    w_type.setdictvalue(space, "__abstractmethods__", w_new)
     w_type.set_abstract(space.is_true(w_new))
 
 def descr_del___abstractmethods__(space, w_type):
     w_type = _check(space, w_type)
-    try:
-        del w_type.dict_w["__abstractmethods__"]
-    except KeyError:
+    if not w_type.deldictvalue(space, space.wrap("__abstractmethods__")):
         raise OperationError(space.w_AttributeError,
                              space.wrap("__abstractmethods__"))
-    w_type.mutated()
     w_type.set_abstract(False)
 
 def descr___subclasses__(space, w_type):

diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -10,7 +10,7 @@
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.rlib.rarithmetic import ovfcheck_float_to_int, intmask, LONG_BIT
 from pypy.rlib.rfloat import (
-    isinf, isnan, INFINITY, NAN, copysign, formatd,
+    isinf, isnan, isfinite, INFINITY, NAN, copysign, formatd,
     DTSF_ADD_DOT_0, DTSF_STR_PRECISION)
 from pypy.rlib.rbigint import rbigint
 from pypy.rlib.objectmodel import we_are_translated
@@ -102,7 +102,7 @@
 
 def float_hex__Float(space, w_float):
     value = w_float.floatval
-    if isinf(value) or isnan(value):
+    if not isfinite(value):
         return str__Float(space, w_float)
     if value == 0.0:
         if copysign(1., value) == -1.:
@@ -136,15 +136,15 @@
 def float2string(space, w_float, code, precision):
     x = w_float.floatval
     # we special-case explicitly inf and nan here
-    if isinf(x):
+    if isfinite(x):
+        s = formatd(x, code, precision, DTSF_ADD_DOT_0)
+    elif isinf(x):
         if x > 0.0:
             s = "inf"
         else:
             s = "-inf"
-    elif isnan(x):
+    else:  # isnan(x):
         s = "nan"
-    else:
-        s = formatd(x, code, precision, DTSF_ADD_DOT_0)
     return space.wrap(s)
 
 def repr__Float(space, w_float):
@@ -179,7 +179,7 @@
     if opname == 'eq' or opname == 'ne':
         def do_compare_bigint(f1, b2):
             """f1 is a float.  b2 is a bigint."""
-            if isinf(f1) or isnan(f1) or math.floor(f1) != f1:
+            if not isfinite(f1) or math.floor(f1) != f1:
                 return opname == 'ne'
             b1 = rbigint.fromfloat(f1)
             res = b1.eq(b2)
@@ -189,7 +189,7 @@
     else:
         def do_compare_bigint(f1, b2):
             """f1 is a float.  b2 is a bigint."""
-            if isinf(f1) or isnan(f1):
+            if not isfinite(f1):
                 return op(f1, 0.0)
             if opname == 'gt' or opname == 'le':
                 # 'float > long'   <==>  'ceil(float) > long'
@@ -457,8 +457,6 @@
 
     if x == 0.0:
         if y < 0.0:
-            if isinf(y):
-                return space.wrap(INFINITY)
             raise OperationError(space.w_ZeroDivisionError,
                                  space.wrap("0.0 cannot be raised to "
                                             "a negative power"))

diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -303,11 +303,10 @@
         return W_ListObject(list_w)
 
     def newdict(self, module=False, instance=False, classofinstance=None,
-                from_strdict_shared=None, strdict=False):
+                strdict=False):
         return W_DictMultiObject.allocate_and_init_instance(
                 self, module=module, instance=instance,
                 classofinstance=classofinstance,
-                from_strdict_shared=from_strdict_shared,
                 strdict=strdict)
 
     def newslice(self, w_start, w_end, w_step):

diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py
--- a/pypy/rpython/extfuncregistry.py
+++ b/pypy/rpython/extfuncregistry.py
@@ -36,6 +36,9 @@
 register_external(rfloat.isnan, [float], bool,
                   export_name="ll_math.ll_math_isnan", sandboxsafe=True,
                   llimpl=ll_math.ll_math_isnan)
+register_external(rfloat.isfinite, [float], bool,
+                  export_name="ll_math.ll_math_isfinite", sandboxsafe=True,
+                  llimpl=ll_math.ll_math_isfinite)
 register_external(rfloat.copysign, [float, float], float,
                   export_name="ll_math.ll_math_copysign", sandboxsafe=True,
                   llimpl=ll_math.ll_math_copysign)

diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -59,7 +59,8 @@
     def find_rewritable_bool(self, op, args):
         try:
             oldopnum = opboolinvers[op.getopnum()]
-            targs = [args[0], args[1], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[0], args[1]],
+                                                              None))
             if self.try_boolinvers(op, targs):
                 return True
         except KeyError:
@@ -67,7 +68,8 @@
 
         try:
             oldopnum = opboolreflex[op.getopnum()] # FIXME: add INT_ADD, INT_MUL
-            targs = [args[1], args[0], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]],
+                                                              None))            
             oldop = self.optimizer.pure_operations.get(targs, None)
             if oldop is not None and oldop.getdescr() is op.getdescr():
                 self.make_equal_to(op.result, self.getvalue(oldop.result))
@@ -77,7 +79,8 @@
 
         try:
             oldopnum = opboolinvers[opboolreflex[op.getopnum()]]
-            targs = [args[1], args[0], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]],
+                                                              None))            
             if self.try_boolinvers(op, targs):
                 return True
         except KeyError:

diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py
--- a/pypy/objspace/std/test/test_typeobject.py
+++ b/pypy/objspace/std/test/test_typeobject.py
@@ -111,6 +111,7 @@
         del X.__abstractmethods__
         X()
         raises(AttributeError, getattr, type, "__abstractmethods__")
+        raises(TypeError, "int.__abstractmethods__ = ('abc', )")
 
     def test_call_type(self):
         assert type(42) is int
@@ -1015,6 +1016,25 @@
             __weakref__ = 42
         assert B().__weakref__ == 42
 
+    def test_change_dict(self):
+        class A(object):
+            pass
+
+        a = A()
+        A.x = 1
+        assert A.__dict__["x"] == 1
+        raises(AttributeError, "del A.__dict__")
+        raises((AttributeError, TypeError), "A.__dict__ = {}")
+
+    def test_mutate_dict(self):
+        class A(object):
+            pass
+
+        a = A()
+        A.x = 1
+        assert A.__dict__["x"] == 1
+        A.__dict__['x'] = 5
+        assert A.x == 5
 
 class AppTestMutableBuiltintypes:
 

diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -219,6 +219,7 @@
     same before and after translation, except for RPython instances on the
     lltypesystem.
     """
+    assert x is not None
     result = object.__hash__(x)
     try:
         x.__dict__['__precomputed_identity_hash'] = result
@@ -267,14 +268,15 @@
     In RPython, floats cannot be used with ints in dicts, anyway.
     """
     from pypy.rlib.rarithmetic import intmask
-    from pypy.rlib.rfloat import isinf, isnan
-    if isinf(f):
-        if f < 0.0:
-            return -271828
-        else:
-            return 314159
-    elif isnan(f):
-        return 0
+    from pypy.rlib.rfloat import isfinite, isinf
+    if not isfinite(f):
+        if isinf(f):
+            if f < 0.0:
+                return -271828
+            else:
+                return 314159
+        else: #isnan(f):
+            return 0
     v, expo = math.frexp(f)
     v *= TAKE_NEXT
     hipart = int(v)

diff --git a/pypy/rlib/rstruct/ieee.py b/pypy/rlib/rstruct/ieee.py
--- a/pypy/rlib/rstruct/ieee.py
+++ b/pypy/rlib/rstruct/ieee.py
@@ -87,12 +87,13 @@
         raise ValueError("invalid size value")
 
     sign = rfloat.copysign(1.0, x) < 0.0
-    if rfloat.isinf(x):
-        mant = r_ulonglong(0)
-        exp = MAX_EXP - MIN_EXP + 2
-    elif rfloat.isnan(x):
-        mant = r_ulonglong(1) << (MANT_DIG-2) # other values possible
-        exp = MAX_EXP - MIN_EXP + 2
+    if not rfloat.isfinite(x):
+        if rfloat.isinf(x):
+            mant = r_ulonglong(0)
+            exp = MAX_EXP - MIN_EXP + 2
+        else:  # rfloat.isnan(x):
+            mant = r_ulonglong(1) << (MANT_DIG-2) # other values possible
+            exp = MAX_EXP - MIN_EXP + 2
     elif x == 0.0:
         mant = r_ulonglong(0)
         exp = 0

diff --git a/pypy/rpython/lltypesystem/module/test/test_ll_math.py b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
--- a/pypy/rpython/lltypesystem/module/test/test_ll_math.py
+++ b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
@@ -22,11 +22,60 @@
         assert ll_math.ll_math_isnan(nan)
         assert not ll_math.ll_math_isnan(inf)
 
+    def test_isfinite(self):
+        inf = 1e200 * 1e200
+        nan = inf / inf
+        assert ll_math.ll_math_isfinite(0.0)
+        assert ll_math.ll_math_isfinite(-42.0)
+        assert not ll_math.ll_math_isfinite(nan)
+        assert not ll_math.ll_math_isnan(inf)
+        assert not ll_math.ll_math_isnan(-inf)
+
+    def test_compiled_isnan(self):
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isnan(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(1e200, 1e200)     # nan
+        assert not f(1e200, 1.0)   # +inf
+        assert not f(1e200, -1.0)  # -inf
+        assert not f(42.5, 2.3)    # +finite
+        assert not f(42.5, -2.3)   # -finite
+
     def test_compiled_isinf(self):
-        def f(x):
-            return ll_math.ll_math_isinf(1. / x)
-        f = compile(f, [float], backendopt=False)
-        assert f(5.5e-309)
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isinf(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(1e200, 1.0)       # +inf
+        assert f(1e200, -1.0)      # -inf
+        assert not f(1e200, 1e200) # nan
+        assert not f(42.5, 2.3)    # +finite
+        assert not f(42.5, -2.3)   # -finite
+
+    def test_compiled_isfinite(self):
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isfinite(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(42.5, 2.3)        # +finite
+        assert f(42.5, -2.3)       # -finite
+        assert not f(1e200, 1.0)   # +inf
+        assert not f(1e200, -1.0)  # -inf
+        assert not f(1e200, 1e200) # nan
+
+
+from pypy.rpython.lltypesystem import lltype
+_A = lltype.GcArray(lltype.Float)
+def normalize(x):
+    # workaround: force the C compiler to cast to a double
+    a = lltype.malloc(_A, 1)
+    a[0] = x
+    import time; time.time()
+    return a[0]
 
 
 def make_test_case((fnname, args, expected), dict):


More information about the Pypy-commit mailing list