[pypy-svn] r73955 - in pypy/branch/cpython-extension/pypy: rlib rlib/test rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Thu Apr 22 10:06:34 CEST 2010


Author: arigo
Date: Thu Apr 22 10:06:32 2010
New Revision: 73955

Added:
   pypy/branch/cpython-extension/pypy/rlib/_rweakkeydict.py
      - copied, changed from r73882, pypy/trunk/pypy/rlib/rweakrefimpl.py
   pypy/branch/cpython-extension/pypy/rlib/_rweakvaldict.py
      - copied, changed from r73882, pypy/trunk/pypy/rlib/rweakrefimpl.py
   pypy/branch/cpython-extension/pypy/rlib/test/test_rweakkeydict.py   (contents, props changed)
   pypy/branch/cpython-extension/pypy/rlib/test/test_rweakvaldict.py
      - copied, changed from r73882, pypy/trunk/pypy/rlib/test/test_rweakref.py
Removed:
   pypy/branch/cpython-extension/pypy/rlib/rweakrefimpl.py
   pypy/branch/cpython-extension/pypy/rlib/test/test_rweakref.py
Modified:
   pypy/branch/cpython-extension/pypy/rlib/rweakref.py
   pypy/branch/cpython-extension/pypy/rpython/lltypesystem/rdict.py
Log:
Add an RPython variant of WeakKeyDictionary.  Currently limited to value
objects that don't have references to too many other objects (see
comment in rlib/_rweakkeydict.py).


Copied: pypy/branch/cpython-extension/pypy/rlib/_rweakkeydict.py (from r73882, pypy/trunk/pypy/rlib/rweakrefimpl.py)
==============================================================================
--- pypy/trunk/pypy/rlib/rweakrefimpl.py	(original)
+++ pypy/branch/cpython-extension/pypy/rlib/_rweakkeydict.py	Thu Apr 22 10:06:32 2010
@@ -1,44 +1,46 @@
 from pypy.objspace.flow.model import Constant
-from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rdict
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rdict
 from pypy.rpython.lltypesystem.llmemory import weakref_create, weakref_deref
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.rclass import getinstancerepr
 from pypy.rpython.rmodel import Repr
-from pypy.rlib.rweakref import RWeakValueDictionary
+from pypy.rlib.rweakref import RWeakKeyDictionary
 from pypy.rlib import jit
+from pypy.rlib.objectmodel import compute_identity_hash
+from pypy.rlib.objectmodel import we_are_translated
 
 
-class WeakValueDictRepr(Repr):
+# Warning: this implementation of RWeakKeyDictionary is not exactly
+# leaking, but can keep around some values for a long time, even after
+# the corresponding keys were freed.  They will be eventually freed if
+# you continue to manipulate the dictionary.  Avoid to use this if the
+# values are objects that might keep alive tons of memory.
+
+
+class WeakKeyDictRepr(Repr):
     def __init__(self, rtyper):
         self.rtyper = rtyper
         self.lowleveltype = lltype.Ptr(WEAKDICT)
         self.dict_cache = {}
 
     def convert_const(self, weakdict):
-        if not isinstance(weakdict, RWeakValueDictionary):
-            raise TyperError("expected an RWeakValueDictionary: %r" % (
+        if not isinstance(weakdict, RWeakKeyDictionary):
+            raise TyperError("expected an RWeakKeyDictionary: %r" % (
                 weakdict,))
         try:
             key = Constant(weakdict)
             return self.dict_cache[key]
         except KeyError:
             self.setup()
+            if weakdict.length() != 0:
+                raise TyperError("got a non-empty prebuilt RWeakKeyDictionary")
             l_dict = ll_new_weakdict()
             self.dict_cache[key] = l_dict
-            bk = self.rtyper.annotator.bookkeeper
-            classdef = bk.getuniqueclassdef(weakdict._valueclass)
-            r_key = rstr.string_repr
-            r_value = getinstancerepr(self.rtyper, classdef)
-            for dictkey, dictvalue in weakdict._dict.items():
-                llkey = r_key.convert_const(dictkey)
-                llvalue = r_value.convert_const(dictvalue)
-                if llvalue:
-                    llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue)
-                    ll_set_nonnull(l_dict, llkey, llvalue)
             return l_dict
 
     def rtype_method_get(self, hop):
-        v_d, v_key = hop.inputargs(self, rstr.string_repr)
+        r_object = getinstancerepr(self.rtyper, None)
+        v_d, v_key = hop.inputargs(self, r_object)
         hop.exception_cannot_occur()
         v_result = hop.gendirectcall(ll_get, v_d, v_key)
         v_result = hop.genop("cast_pointer", [v_result],
@@ -46,16 +48,19 @@
         return v_result
 
     def rtype_method_set(self, hop):
-        v_d, v_key, v_value = hop.inputargs(self, rstr.string_repr,
-                                            hop.args_r[2])
+        r_object = getinstancerepr(self.rtyper, None)
+        v_d, v_key, v_value = hop.inputargs(self, r_object, r_object)
         hop.exception_cannot_occur()
         if hop.args_s[2].is_constant() and hop.args_s[2].const is None:
             hop.gendirectcall(ll_set_null, v_d, v_key)
         else:
-            v_value = hop.genop("cast_pointer", [v_value],
-                                resulttype=rclass.OBJECTPTR)
             hop.gendirectcall(ll_set, v_d, v_key, v_value)
 
+    def rtype_method_length(self, hop):
+        v_d, = hop.inputargs(self)
+        hop.exception_cannot_occur()
+        return hop.gendirectcall(ll_length, v_d)
+
 
 def specialize_make_weakdict(hop):
     hop.exception_cannot_occur()
@@ -65,33 +70,47 @@
 # ____________________________________________________________
 
 
+NULLVALUE = lltype.nullptr(rclass.OBJECTPTR.TO)
 WEAKDICTENTRY = lltype.Struct("weakdictentry",
-                              ("key", lltype.Ptr(rstr.STR)),
-                              ("value", llmemory.WeakRefPtr))
+                              ("key", llmemory.WeakRefPtr),
+                              ("value", rclass.OBJECTPTR),
+                              ("f_hash", lltype.Signed))
+
+def ll_debugrepr(x):
+    if x:
+        h = compute_identity_hash(x)
+    else:
+        h = 0
+    return '<%x>' % (h,)
 
 def ll_valid(entries, i):
-    return (bool(entries[i].value) and
-            bool(weakref_deref(rclass.OBJECTPTR, entries[i].value)))
+    key = entries[i].key
+    if not key:
+        return False
+    elif weakref_deref(rclass.OBJECTPTR, key):
+        return True
+    else:
+        # The entry might be a dead weakref still holding a strong
+        # reference to the value; for this case, we clear the old
+        # value from the entry, if any.
+        entries[i].value = NULLVALUE
+        return False
 
 def ll_everused(entries, i):
-    return bool(entries[i].value)
-
-def ll_hash(entries, i):
-    return str_fasthashfn(entries[i].key)
-str_fasthashfn = rstr.string_repr.get_ll_fasthash_function()
+    return bool(entries[i].key)
 
 entrymeths = {
     'allocate': lltype.typeMethod(rdict._ll_malloc_entries),
     'delete': rdict._ll_free_entries,
     'valid': ll_valid,
     'everused': ll_everused,
-    'hash': ll_hash,
+    'hash': rdict.ll_hash_from_cache,
+    'no_direct_compare': True,
     }
 WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY,
                                     adtmeths=entrymeths,
-                                    hints={'weakarray': 'value'})
-
-ll_strhash = rstr.LLHelpers.ll_strhash
+                                    hints={'weakarray': 'key'})
+# NB. the 'hints' is not used so far ^^^
 
 @jit.dont_look_inside
 def ll_new_weakdict():
@@ -103,14 +122,15 @@
 
 @jit.dont_look_inside
 def ll_get(d, llkey):
-    hash = ll_strhash(llkey)
+    hash = compute_identity_hash(llkey)
     i = rdict.ll_dict_lookup(d, llkey, hash)
-    #llop.debug_print(lltype.Void, i, 'get')
-    valueref = d.entries[i].value
-    if valueref:
-        return weakref_deref(rclass.OBJECTPTR, valueref)
-    else:
-        return lltype.nullptr(rclass.OBJECTPTR.TO)
+    #llop.debug_print(lltype.Void, i, 'get', hex(hash),
+    #                 ll_debugrepr(d.entries[i].key),
+    #                 ll_debugrepr(d.entries[i].value))
+    # NB. ll_valid() above was just called at least on entry i, so if
+    # it is an invalid entry with a dead weakref, the value was reset
+    # to NULLVALUE.
+    return d.entries[i].value
 
 @jit.dont_look_inside
 def ll_set(d, llkey, llvalue):
@@ -121,51 +141,70 @@
 
 @jit.dont_look_inside
 def ll_set_nonnull(d, llkey, llvalue):
-    hash = ll_strhash(llkey)
-    valueref = weakref_create(llvalue)    # GC effects here, before the rest
+    hash = compute_identity_hash(llkey)
+    keyref = weakref_create(llkey)    # GC effects here, before the rest
     i = rdict.ll_dict_lookup(d, llkey, hash)
     everused = d.entries.everused(i)
-    d.entries[i].key = llkey
-    d.entries[i].value = valueref
-    #llop.debug_print(lltype.Void, i, 'stored')
+    d.entries[i].key = keyref
+    d.entries[i].value = llvalue
+    d.entries[i].f_hash = hash
+    #llop.debug_print(lltype.Void, i, 'stored', hex(hash),
+    #                 ll_debugrepr(llkey),
+    #                 ll_debugrepr(llvalue))
     if not everused:
         d.num_pristine_entries -= 1
-        if d.num_pristine_entries <= len(d.entries) / 3:
+        if d.num_pristine_entries * 3 <= len(d.entries):
             #llop.debug_print(lltype.Void, 'RESIZE')
             ll_weakdict_resize(d)
 
 @jit.dont_look_inside
 def ll_set_null(d, llkey):
-    hash = ll_strhash(llkey)
+    hash = compute_identity_hash(llkey)
     i = rdict.ll_dict_lookup(d, llkey, hash)
     if d.entries.everused(i):
         # If the entry was ever used, clean up its key and value.
         # We don't store a NULL value, but a dead weakref, because
         # the entry must still be marked as everused().
-        d.entries[i].value = llmemory.dead_wref
-        d.entries[i].key = lltype.nullptr(rstr.STR)
+        d.entries[i].key = llmemory.dead_wref
+        d.entries[i].value = NULLVALUE
         #llop.debug_print(lltype.Void, i, 'zero')
 
-def ll_weakdict_resize(d):
-    # first set num_items to its correct, up-to-date value
+def ll_update_num_items(d):
     entries = d.entries
     num_items = 0
     for i in range(len(entries)):
         if entries.valid(i):
             num_items += 1
     d.num_items = num_items
+
+def ll_weakdict_resize(d):
+    # first set num_items to its correct, up-to-date value
+    ll_update_num_items(d)
     rdict.ll_dict_resize(d)
 
-str_keyeq = lltype.staticAdtMethod(rstr.string_repr.get_ll_eq_function())
+def ll_keyeq(d, weakkey1, realkey2):
+    # only called by ll_dict_lookup() with the first arg coming from an
+    # entry.key, and the 2nd arg being the argument to ll_dict_lookup().
+    if not weakkey1:
+        assert bool(realkey2)
+        return False
+    return weakref_deref(rclass.OBJECTPTR, weakkey1) == realkey2
+
+ at jit.dont_look_inside
+def ll_length(d):
+    # xxx slow, but it's only for debugging
+    ll_update_num_items(d)
+    #llop.debug_print(lltype.Void, 'length:', d.num_items)
+    return d.num_items
 
 dictmeths = {
     'll_get': ll_get,
     'll_set': ll_set,
-    'keyeq': str_keyeq,
+    'keyeq': ll_keyeq,
     'paranoia': False,
     }
 
-WEAKDICT = lltype.GcStruct("weakdict",
+WEAKDICT = lltype.GcStruct("weakkeydict",
                            ("num_items", lltype.Signed),
                            ("num_pristine_entries", lltype.Signed),
                            ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)),

Copied: pypy/branch/cpython-extension/pypy/rlib/_rweakvaldict.py (from r73882, pypy/trunk/pypy/rlib/rweakrefimpl.py)
==============================================================================
--- pypy/trunk/pypy/rlib/rweakrefimpl.py	(original)
+++ pypy/branch/cpython-extension/pypy/rlib/_rweakvaldict.py	Thu Apr 22 10:06:32 2010
@@ -46,14 +46,13 @@
         return v_result
 
     def rtype_method_set(self, hop):
+        r_object = getinstancerepr(self.rtyper, None)
         v_d, v_key, v_value = hop.inputargs(self, rstr.string_repr,
-                                            hop.args_r[2])
+                                            r_object)
         hop.exception_cannot_occur()
         if hop.args_s[2].is_constant() and hop.args_s[2].const is None:
             hop.gendirectcall(ll_set_null, v_d, v_key)
         else:
-            v_value = hop.genop("cast_pointer", [v_value],
-                                resulttype=rclass.OBJECTPTR)
             hop.gendirectcall(ll_set, v_d, v_key, v_value)
 
 
@@ -70,8 +69,8 @@
                               ("value", llmemory.WeakRefPtr))
 
 def ll_valid(entries, i):
-    return (bool(entries[i].value) and
-            bool(weakref_deref(rclass.OBJECTPTR, entries[i].value)))
+    value = entries[i].value
+    return bool(value) and bool(weakref_deref(rclass.OBJECTPTR, value))
 
 def ll_everused(entries, i):
     return bool(entries[i].value)
@@ -90,6 +89,7 @@
 WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY,
                                     adtmeths=entrymeths,
                                     hints={'weakarray': 'value'})
+# NB. the 'hints' is not used so far ^^^
 
 ll_strhash = rstr.LLHelpers.ll_strhash
 
@@ -130,7 +130,7 @@
     #llop.debug_print(lltype.Void, i, 'stored')
     if not everused:
         d.num_pristine_entries -= 1
-        if d.num_pristine_entries <= len(d.entries) / 3:
+        if d.num_pristine_entries * 3 <= len(d.entries):
             #llop.debug_print(lltype.Void, 'RESIZE')
             ll_weakdict_resize(d)
 
@@ -165,7 +165,7 @@
     'paranoia': False,
     }
 
-WEAKDICT = lltype.GcStruct("weakdict",
+WEAKDICT = lltype.GcStruct("weakvaldict",
                            ("num_items", lltype.Signed),
                            ("num_pristine_entries", lltype.Signed),
                            ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)),

Modified: pypy/branch/cpython-extension/pypy/rlib/rweakref.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/rlib/rweakref.py	(original)
+++ pypy/branch/cpython-extension/pypy/rlib/rweakref.py	Thu Apr 22 10:06:32 2010
@@ -1,6 +1,7 @@
 """
 Weakref support in RPython.  Supports ref() without callbacks,
-and a limited version of WeakValueDictionary.  LLType only for now!
+a form of WeakKeyDictionary, and a limited version of WeakValueDictionary.
+LLType only for now!
 """
 
 import weakref
@@ -27,6 +28,36 @@
             self._dict[key] = value
 
 
+class RWeakKeyDictionary(object):
+    """A dictionary containing weak keys.
+    Keys and values must be instances.
+    Prebuilt RWeakKeyDictionaries must be empty.
+    """
+
+    def __init__(self, keyclass, valueclass):
+        self._dict = weakref.WeakKeyDictionary()
+        self._keyclass = keyclass
+        self._valueclass = valueclass
+
+    def get(self, key):
+        """Get the value associated to 'key', or None by default."""
+        assert isinstance(key, self._keyclass)
+        return self._dict.get(key, None)
+
+    def set(self, key, value):
+        """Set the key/value pair (or delete it if value is None)."""
+        assert isinstance(key, self._keyclass)
+        if value is None:
+            self._dict.pop(key, None)
+        else:
+            assert isinstance(value, self._valueclass)
+            self._dict[key] = value
+
+    def length(self):
+        """Mostly for debugging.  Slow, don't use in real code."""
+        return len(self._dict)
+
+
 # ____________________________________________________________
 
 from pypy.rpython import extregistry
@@ -41,8 +72,8 @@
         self.valueclassdef = valueclassdef
 
     def rtyper_makerepr(self, rtyper):
-        from pypy.rlib import rweakrefimpl
-        return rweakrefimpl.WeakValueDictRepr(rtyper)
+        from pypy.rlib import _rweakvaldict
+        return _rweakvaldict.WeakValueDictRepr(rtyper)
 
     def rtyper_makekey_ex(self, rtyper):
         return self.__class__,
@@ -65,14 +96,11 @@
     _about_ = RWeakValueDictionary
 
     def compute_result_annotation(self, s_valueclass):
-        assert isinstance(s_valueclass, annmodel.SomePBC)
-        assert s_valueclass.is_constant()
-        [desc] = s_valueclass.descriptions
-        return SomeWeakValueDict(desc.getuniqueclassdef())
+        return SomeWeakValueDict(_getclassdef(s_valueclass))
 
     def specialize_call(self, hop):
-        from pypy.rlib import rweakrefimpl
-        return rweakrefimpl.specialize_make_weakdict(hop)
+        from pypy.rlib import _rweakvaldict
+        return _rweakvaldict.specialize_make_weakdict(hop)
 
 class Entry(extregistry.ExtRegistryEntry):
     _type_ = RWeakValueDictionary
@@ -81,3 +109,65 @@
         bk = self.bookkeeper
         x = self.instance
         return SomeWeakValueDict(bk.getuniqueclassdef(x._valueclass))
+
+def _getclassdef(s_instance):
+    assert isinstance(s_instance, annmodel.SomePBC)
+    assert s_instance.is_constant()
+    [desc] = s_instance.descriptions
+    return desc.getuniqueclassdef()
+
+# ____________________________________________________________
+
+class SomeWeakKeyDict(annmodel.SomeObject):
+    knowntype = RWeakKeyDictionary
+
+    def __init__(self, keyclassdef, valueclassdef):
+        self.keyclassdef = keyclassdef
+        self.valueclassdef = valueclassdef
+
+    def rtyper_makerepr(self, rtyper):
+        from pypy.rlib import _rweakkeydict
+        return _rweakkeydict.WeakKeyDictRepr(rtyper)
+
+    def rtyper_makekey_ex(self, rtyper):
+        return self.__class__,
+
+    def method_get(self, s_key):
+        assert isinstance(s_key, annmodel.SomeInstance)
+        assert s_key.classdef.issubclass(self.keyclassdef)
+        return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)
+
+    def method_set(self, s_key, s_value):
+        s_oldvalue = self.method_get(s_key)
+        assert s_oldvalue.contains(s_value)
+
+    def method_length(self):
+        return annmodel.SomeInteger(nonneg=True)
+
+class __extend__(pairtype(SomeWeakKeyDict, SomeWeakKeyDict)):
+    def union((s_wkd1, s_wkd2)):
+        if s_wkd1.keyclassdef is not s_wkd2.keyclassdef:
+            return SomeObject() # not the same key class! complain...
+        if s_wkd1.valueclassdef is not s_wkd2.valueclassdef:
+            return SomeObject() # not the same value class! complain...
+        return SomeWeakKeyDict(s_wkd1.keyclassdef, s_wkd1.valueclassdef)
+
+class Entry(extregistry.ExtRegistryEntry):
+    _about_ = RWeakKeyDictionary
+
+    def compute_result_annotation(self, s_keyclass, s_valueclass):
+        return SomeWeakKeyDict(_getclassdef(s_keyclass),
+                               _getclassdef(s_valueclass))
+
+    def specialize_call(self, hop):
+        from pypy.rlib import _rweakkeydict
+        return _rweakkeydict.specialize_make_weakdict(hop)
+
+class Entry(extregistry.ExtRegistryEntry):
+    _type_ = RWeakKeyDictionary
+
+    def compute_annotation(self):
+        bk = self.bookkeeper
+        x = self.instance
+        return SomeWeakKeyDict(bk.getuniqueclassdef(x._keyclass),
+                               bk.getuniqueclassdef(x._valueclass))

Added: pypy/branch/cpython-extension/pypy/rlib/test/test_rweakkeydict.py
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/rlib/test/test_rweakkeydict.py	Thu Apr 22 10:06:32 2010
@@ -0,0 +1,137 @@
+import py
+from pypy.rlib import rgc
+from pypy.rlib.rweakref import RWeakKeyDictionary
+from pypy.rpython.test.test_llinterp import interpret
+
+class KX(object):
+    pass
+
+class KY(KX):
+    pass
+
+class VX(object):
+    pass
+
+class VY(VX):
+    pass
+
+
+def make_test(loop=100, prebuilt=None):
+    def g(d):
+        assert d.get(KX()) is None
+        assert d.get(KY()) is None
+        k1 = KX(); k2 = KX(); k3 = KX()
+        v1 = VX(); v2 = VX(); v3 = VX()
+        d.set(k1, v1)
+        d.set(k2, v2)
+        d.set(k3, v3)
+        assert d.get(k1) is v1
+        assert d.get(k2) is v2
+        assert d.get(k3) is v3
+        assert d.get(KX()) is None
+        assert d.length() == 3
+        return k1, k3, v1, v2, v3    # k2 dies
+    def f():
+        d = prebuilt
+        if d is None:
+            d = RWeakKeyDictionary(KX, VX)
+        k1, k3, v1, v2, v3 = g(d)
+        rgc.collect(); rgc.collect()
+        assert d.get(k1) is v1
+        assert d.get(k3) is v3
+        assert d.get(k1) is not v2
+        assert d.get(k3) is not v2
+        assert d.length() == 2
+        d.set(k1, None)
+        assert d.get(k1) is None
+        assert d.get(k3) is v3
+        assert d.length() == 1
+        # resizing should also work
+        lots_of_keys = [KX() for i in range(loop)]
+        for k in lots_of_keys:
+            d.set(k, v1)
+        for k in lots_of_keys:
+            assert d.get(k) is v1
+        assert d.get(k1) is None
+        assert d.get(k3) is v3
+        assert d.length() == loop + 1
+        # a subclass
+        ky = KY()
+        vy = VY()
+        d.set(ky, vy)
+        assert d.get(ky) is vy
+        assert d.length() == loop + 2
+        # deleting by storing Nones
+        for k in lots_of_keys:
+            d.set(k, None)
+        for k in lots_of_keys:
+            assert d.get(k) is None
+        assert d.get(k1) is None
+        assert d.get(k3) is v3
+        assert d.get(ky) is vy
+        assert d.length() == 2
+    return f
+
+def test_RWeakKeyDictionary():
+    make_test()()
+
+def test_rpython_RWeakKeyDictionary():
+    interpret(make_test(loop=12), [])
+
+def test_rpython_prebuilt():
+    f = make_test(loop=12, prebuilt=RWeakKeyDictionary(KX, VX))
+    interpret(f, [])
+
+def test_rpython_merge_RWeakKeyDictionary():
+    empty = RWeakKeyDictionary(KX, VX)
+    def f(n):
+        k = KX()
+        v = VX()
+        if n:
+            d = empty
+        else:
+            d = RWeakKeyDictionary(KX, VX)
+            d.set(k, v)
+        return d.get(k) is v
+    assert f(0)
+    assert interpret(f, [0])
+    assert not f(1)
+    assert not interpret(f, [1])
+
+
+def test_rpython_merge_RWeakKeyDictionary2():
+    class A(object):
+        def __init__(self):
+            self.d = RWeakKeyDictionary(KX, A)
+        def f(self, key):
+            a = A()
+            self.d.set(key, a)
+            return a
+    empty = A()
+    def f(x):
+        a = A()
+        if x:
+            a = empty
+        k = KX()
+        a2 = a.f(k)
+        assert a.d.get(k) is a2
+    f(0)
+    interpret(f, [0])
+    f(1)
+    interpret(f, [1])
+
+    def g(x):
+        if x:
+            d = RWeakKeyDictionary(KX, VX)
+        else:
+            d = RWeakKeyDictionary(KY, VX)
+        d.set(KX(), VX())
+    py.test.raises(Exception, interpret, g, [1])
+
+    def g(x):
+        if x:
+            d = RWeakKeyDictionary(KX, VX)
+        else:
+            d = RWeakKeyDictionary(KX, VY)
+        d.set(KX(), VX())
+    py.test.raises(Exception, interpret, g, [1])

Copied: pypy/branch/cpython-extension/pypy/rlib/test/test_rweakvaldict.py (from r73882, pypy/trunk/pypy/rlib/test/test_rweakref.py)
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rweakref.py	(original)
+++ pypy/branch/cpython-extension/pypy/rlib/test/test_rweakvaldict.py	Thu Apr 22 10:06:32 2010
@@ -130,5 +130,4 @@
         else:
             d = RWeakValueDictionary(Y)
         d.set("x", X())
-        return 41
     py.test.raises(Exception, interpret, g, [1])

Modified: pypy/branch/cpython-extension/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/branch/cpython-extension/pypy/rpython/lltypesystem/rdict.py	Thu Apr 22 10:06:32 2010
@@ -508,12 +508,14 @@
 
 def ll_dict_lookup(d, key, hash):
     entries = d.entries
+    ENTRIES = lltype.typeOf(entries).TO
+    direct_compare = not hasattr(ENTRIES, 'no_direct_compare')
     mask = len(entries) - 1
     i = hash & mask
     # do the first try before any looping 
     if entries.valid(i):
         checkingkey = entries[i].key
-        if checkingkey == key:
+        if direct_compare and checkingkey == key:
             return i   # found the entry
         if d.keyeq is not None and entries.hash(i) == hash:
             # correct hash, maybe the key is e.g. a different pointer to
@@ -548,7 +550,7 @@
             return freeslot
         elif entries.valid(i):
             checkingkey = entries[i].key
-            if checkingkey == key:
+            if direct_compare and checkingkey == key:
                 return i
             if d.keyeq is not None and entries.hash(i) == hash:
                 # correct hash, maybe the key is e.g. a different pointer to



More information about the Pypy-commit mailing list