[pypy-svn] r49232 - in pypy/dist/pypy: annotation objspace/std rlib rpython rpython/lltypesystem rpython/memory/test rpython/ootypesystem rpython/ootypesystem/test rpython/test

arigo at codespeak.net arigo at codespeak.net
Fri Nov 30 19:20:54 CET 2007


Author: arigo
Date: Fri Nov 30 19:20:51 2007
New Revision: 49232

Modified:
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/objspace/std/default.py
   pypy/dist/pypy/rlib/objectmodel.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/memory/test/test_gc.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/dist/pypy/rpython/ootypesystem/rclass.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py
   pypy/dist/pypy/rpython/rmodel.py
   pypy/dist/pypy/rpython/rtuple.py
   pypy/dist/pypy/rpython/test/test_llinterp.py
   pypy/dist/pypy/rpython/test/test_rbuiltin.py
   pypy/dist/pypy/rpython/test/test_rclass.py
Log:
issue325 testing

It's too easy to use id() in RPython and forget that it's actually a
pretty advanced operation on top of moving GCs.  This replaces it with
two functions in the objectmodel module, one which implements the full
semantics of id() and another which just returns the current address as
an integer.


Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Fri Nov 30 19:20:51 2007
@@ -119,8 +119,11 @@
         getbookkeeper().count('oct', obj)
         return SomeString()
 
-    def id(obj): # xxx
-        return SomeInteger()
+    def id(obj):
+        raise Exception("cannot use id() in RPython; pick one of:\n"
+                        "\t\t objectmodel.compute_unique_id()\n"
+                        "\t\t hash()\n"
+                        "\t\t objectmodel.current_object_addr_as_int()")
 
     def int(obj):
         return SomeInteger()

Modified: pypy/dist/pypy/objspace/std/default.py
==============================================================================
--- pypy/dist/pypy/objspace/std/default.py	(original)
+++ pypy/dist/pypy/objspace/std/default.py	Fri Nov 30 19:20:51 2007
@@ -1,6 +1,7 @@
 """Default implementation for some operation."""
 
 from pypy.objspace.std.objspace import *
+from pypy.rlib import objectmodel
 
 
 # The following default implementations are used before delegation is tried.
@@ -8,7 +9,7 @@
 
 def id__ANY(space, w_obj):
     #print 'id:', w_obj
-    return space.wrap(id(w_obj))
+    return space.wrap(objectmodel.compute_unique_id(w_obj))
 
 # __init__ should succeed if called internally as a multimethod
 

Modified: pypy/dist/pypy/rlib/objectmodel.py
==============================================================================
--- pypy/dist/pypy/rlib/objectmodel.py	(original)
+++ pypy/dist/pypy/rlib/objectmodel.py	Fri Nov 30 19:20:51 2007
@@ -128,6 +128,80 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
 
 # ____________________________________________________________
+#
+# id-like functions.
+# In addition, RPython supports hash(x) on RPython instances,
+# returning a number that is not guaranteed to be unique but
+# that doesn't change over time for a given 'x'.
+
+def compute_unique_id(x):
+    """RPython equivalent of id(x).  The 'x' must be an RPython instance.
+    This operation can be very costly depending on the garbage collector.
+    To remind you of this fact, we don't support id(x) directly.
+    """
+    return id(x)      # XXX need to return r_longlong on some platforms
+
+def current_object_addr_as_int(x):
+    """A cheap version of id(x).  The current memory location of an
+    instance can change over time for moving GCs.  Also note that on
+    ootypesystem this typically doesn't return the real address but
+    just the same as hash(x).
+    """
+    from pypy.rlib.rarithmetic import intmask
+    return intmask(id(x))
+
+class Entry(ExtRegistryEntry):
+    _about_ = compute_unique_id
+
+    def compute_result_annotation(self, s_x):
+        from pypy.annotation import model as annmodel
+        assert isinstance(s_x, annmodel.SomeInstance)
+        return annmodel.SomeInteger()
+
+    def specialize_call(self, hop):
+        vobj, = hop.inputargs(hop.args_r[0])
+        if hop.rtyper.type_system.name == 'lltypesystem':
+            from pypy.rpython.lltypesystem import lltype
+            if isinstance(vobj.concretetype, lltype.Ptr):
+                return hop.genop('gc_id', [vobj],
+                                 resulttype = lltype.Signed)
+        elif hop.rtyper.type_system.name == 'ootypesystem':
+            from pypy.rpython.ootypesystem import ootype
+            if isinstance(vobj.concretetype, ootype.Instance):
+                # XXX wrong implementation for now, fix me
+                from pypy.rpython.rmodel import warning
+                warning("compute_unique_id() is not fully supported on ootype")
+                return hop.genop('ooidentityhash', [vobj],
+                                 resulttype = ootype.Signed)
+        from pypy.rpython.error import TyperError
+        raise TyperError("compute_unique_id() cannot be applied to %r" % (
+            vobj.concretetype,))
+
+class Entry(ExtRegistryEntry):
+    _about_ = current_object_addr_as_int
+
+    def compute_result_annotation(self, s_x):
+        from pypy.annotation import model as annmodel
+        assert isinstance(s_x, annmodel.SomeInstance)
+        return annmodel.SomeInteger()
+
+    def specialize_call(self, hop):
+        vobj, = hop.inputargs(hop.args_r[0])
+        if hop.rtyper.type_system.name == 'lltypesystem':
+            from pypy.rpython.lltypesystem import lltype
+            if isinstance(vobj.concretetype, lltype.Ptr):
+                return hop.genop('cast_ptr_to_int', [vobj],
+                                 resulttype = lltype.Signed)
+        elif hop.rtyper.type_system.name == 'ootypesystem':
+            from pypy.rpython.ootypesystem import ootype
+            if isinstance(vobj.concretetype, ootype.Instance):
+                return hop.genop('ooidentityhash', [vobj],
+                                 resulttype = ootype.Signed)
+        from pypy.rpython.error import TyperError
+        raise TyperError("current_object_addr_as_int() cannot be applied to"
+                         " %r" % (vobj.concretetype,))
+
+# ____________________________________________________________
 
 def debug_assert(x, msg):
     """After translation to C, this becomes an RPyAssert."""

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Fri Nov 30 19:20:51 2007
@@ -471,7 +471,7 @@
     'instanceof':           LLOp(oo=True, canfold=True),
     'classof':              LLOp(oo=True, canfold=True),
     'subclassof':           LLOp(oo=True, canfold=True),
-    'ooidentityhash':       LLOp(oo=True, sideeffects=False),
+    'ooidentityhash':       LLOp(oo=True, sideeffects=False),  # not an id()!
     'oostring':             LLOp(oo=True, sideeffects=False),
     'ooparse_int':          LLOp(oo=True, canraise=(ValueError,)),
     'ooparse_float':        LLOp(oo=True, canraise=(ValueError,)),

Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Fri Nov 30 19:20:51 2007
@@ -701,7 +701,7 @@
         return 0    # for None
     cached = ins.hash_cache
     if cached == 0:
-       cached = ins.hash_cache = intmask(id(ins))     # XXX issue325
+       cached = ins.hash_cache = cast_ptr_to_int(ins)
     return cached
 
 def ll_inst_type(obj):

Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_gc.py	Fri Nov 30 19:20:51 2007
@@ -7,6 +7,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import compute_unique_id
 
 
 def stdout_ignore_ll_functions(msg):
@@ -262,14 +263,14 @@
         def f():
             a2 = A()
             a3 = A()
-            id1 = id(a1)
-            id2 = id(a2)
-            id3 = id(a3)
+            id1 = compute_unique_id(a1)
+            id2 = compute_unique_id(a2)
+            id3 = compute_unique_id(a3)
             llop.gc__collect(lltype.Void)
             error = 0
-            if id1 != id(a1): error += 1
-            if id2 != id(a2): error += 2
-            if id3 != id(a3): error += 4
+            if id1 != compute_unique_id(a1): error += 1
+            if id2 != compute_unique_id(a2): error += 2
+            if id3 != compute_unique_id(a3): error += 4
             return error
         res = self.interpret(f, [])
         assert res == 0

Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	Fri Nov 30 19:20:51 2007
@@ -8,6 +8,7 @@
 from pypy.rpython.memory.gctransform import stacklessframework
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR
+from pypy.rlib.objectmodel import compute_unique_id
 from pypy import conftest
 
 INT_SIZE = struct.calcsize("i")   # only for estimates
@@ -428,14 +429,14 @@
         def func():
             a2 = A()
             a3 = A()
-            id1 = id(a1)
-            id2 = id(a2)
-            id3 = id(a3)
+            id1 = compute_unique_id(a1)
+            id2 = compute_unique_id(a2)
+            id3 = compute_unique_id(a3)
             llop.gc__collect(lltype.Void)
             error = 0
-            if id1 != id(a1): error += 1
-            if id2 != id(a2): error += 2
-            if id3 != id(a3): error += 4
+            if id1 != compute_unique_id(a1): error += 1
+            if id2 != compute_unique_id(a2): error += 2
+            if id3 != compute_unique_id(a3): error += 4
             return error
         run = self.runner(func)
         res = run([])
@@ -456,7 +457,7 @@
             # remember the ids, it will trigger some collections itself
             i = 0
             while i < len(alist):
-                idarray[i] = id(alist[i])
+                idarray[i] = compute_unique_id(alist[i])
                 i += 1
             j = 0
             while j < 2:
@@ -464,7 +465,7 @@
                     [A() for i in range(20)]
                 i = 0
                 while i < len(alist):
-                    assert idarray[i] == id(alist[i])
+                    assert idarray[i] == compute_unique_id(alist[i])
                     i += 1
                 j += 1
             lltype.free(idarray, flavor='raw')

Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rclass.py	Fri Nov 30 19:20:51 2007
@@ -449,10 +449,6 @@
             cmeta = inputconst(ootype.Void, "meta")
             return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE)
 
-    def rtype_id(self, hop):
-        vinst, = hop.inputargs(self)
-        return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed)
-
     def null_instance(self):
         return ootype.null(self.lowleveltype)
 

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py	Fri Nov 30 19:20:51 2007
@@ -437,6 +437,7 @@
     assert res == ~0x0200 & 0x3ff
 
 def test_hash_preservation():
+    from pypy.rlib.objectmodel import current_object_addr_as_int
     class C:
         pass
     class D(C):
@@ -445,7 +446,7 @@
         d2 = D()
         # xxx we assume that the identityhash doesn't change from
         #     one line to the next
-        current_identityhash = id(d2)
+        current_identityhash = current_object_addr_as_int(d2)
         instance_hash = hash(d2)
         return ((current_identityhash & sys.maxint) ==
                 (instance_hash & sys.maxint))

Modified: pypy/dist/pypy/rpython/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rmodel.py	(original)
+++ pypy/dist/pypy/rpython/rmodel.py	Fri Nov 30 19:20:51 2007
@@ -215,13 +215,6 @@
         else:
             return hop.genop('int_is_true', [vlen], resulttype=Bool)
 
-    def rtype_id(self, hop):
-        if not isinstance(self.lowleveltype, Ptr):
-            raise TyperError('id() of an instance of the non-pointer %r' % (
-                self,))
-        vobj, = hop.inputargs(self)
-        return hop.genop('gc_id', [vobj], resulttype=Signed)
-
     def rtype_hash(self, hop):
         ll_hash = self.get_ll_hash_function()
         v, = hop.inputargs(self)

Modified: pypy/dist/pypy/rpython/rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/rtuple.py	(original)
+++ pypy/dist/pypy/rpython/rtuple.py	Fri Nov 30 19:20:51 2007
@@ -204,9 +204,6 @@
     def rtype_len(self, hop):
         return hop.inputconst(Signed, len(self.items_r))
 
-    def rtype_id(self, hop):
-        raise TyperError("cannot ask for the id() of a tuple")
-
     def get_ll_eq_function(self):
         return gen_eq_function(self.items_r)
 

Modified: pypy/dist/pypy/rpython/test/test_llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_llinterp.py	(original)
+++ pypy/dist/pypy/rpython/test/test_llinterp.py	Fri Nov 30 19:20:51 2007
@@ -409,12 +409,13 @@
     assert res == 5
 
 def test_id():
+    from pypy.rlib.objectmodel import compute_unique_id
     def getids(i, j):
         e1 = ExampleClass(1)
         e2 = ExampleClass(2)
         a = [e1, e2][i]
         b = [e1, e2][j]
-        return (id(a) == id(b)) == (a is b)
+        return (compute_unique_id(a) == compute_unique_id(b)) == (a is b)
     for i in [0, 1]:
         for j in [0, 1]:
             result = interpret(getids, [i, j])

Modified: pypy/dist/pypy/rpython/test/test_rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rbuiltin.py	Fri Nov 30 19:20:51 2007
@@ -4,7 +4,7 @@
 from pypy.rlib.objectmodel import running_on_llinterp, debug_llinterpcall
 from pypy.rpython.lltypesystem import lltype
 from pypy.tool import udir
-from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.rarithmetic import r_uint, intmask, r_longlong
 from pypy.annotation.builtin import *
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 from pypy.rpython.lltypesystem.rffi import SHORT
@@ -429,6 +429,26 @@
         res = f(7)
         assert res == 321
 
+    def test_id(self):
+        from pypy.rlib.objectmodel import compute_unique_id
+        from pypy.rlib.objectmodel import current_object_addr_as_int
+        class A:
+            pass
+        def fn():
+            a1 = A()
+            a2 = A()
+            return (compute_unique_id(a1), current_object_addr_as_int(a1),
+                    compute_unique_id(a2), current_object_addr_as_int(a2))
+        res = self.interpret(fn, [])
+        x0, x1, x2, x3 = self.ll_unpack_tuple(res, 4)
+        assert isinstance(x0, (int, r_longlong))
+        assert isinstance(x1, int)
+        assert isinstance(x2, (int, r_longlong))
+        assert isinstance(x3, int)
+        assert x1 == intmask(x0)     # at least on top of llinterp
+        assert x3 == intmask(x2)     # at least on top of llinterp
+        assert x0 != x2
+
 class TestLLtype(BaseTestRbuiltin, LLRtypeMixin):
 
     def test_isinstance_obj(self):

Modified: pypy/dist/pypy/rpython/test/test_rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rclass.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rclass.py	Fri Nov 30 19:20:51 2007
@@ -390,6 +390,7 @@
         assert res == ~0x0200 & 0x3ff
 
     def test_hash_preservation(self):
+        from pypy.rlib.objectmodel import current_object_addr_as_int
         class C:
             pass
         class D(C):
@@ -399,7 +400,9 @@
         def f():
             d2 = D()
             # xxx check for this CPython peculiarity for now:
-            x = (hash(d2) & sys.maxint) == (id(d2) & sys.maxint)
+            # (this is true on top of the llinterp too)
+            x = ((hash(d2) & sys.maxint) ==
+                 (current_object_addr_as_int(d2) & sys.maxint))
             return x, hash(c)+hash(d)
 
         res = self.interpret(f, [])
@@ -688,11 +691,14 @@
         assert summary(graph) == {"setfield": 2}
         
     def test_instance_repr(self):
+        from pypy.rlib.objectmodel import current_object_addr_as_int
         class FooBar(object):
             pass
         def f():
             x = FooBar()
-            return id(x), str(x)
+            # on lltype, the RPython-level repr of an instance contains the
+            # current object address
+            return current_object_addr_as_int(x), str(x)
 
         res = self.interpret(f, [])
         xid, xstr = self.ll_unpack_tuple(res, 2)



More information about the Pypy-commit mailing list