[pypy-svn] r47103 - in pypy/branch/rdict-index-based2/pypy/rpython: lltypesystem test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Oct 2 20:45:01 CEST 2007
Author: cfbolz
Date: Tue Oct 2 20:45:00 2007
New Revision: 47103
Modified:
pypy/branch/rdict-index-based2/pypy/rpython/lltypesystem/rdict.py
pypy/branch/rdict-index-based2/pypy/rpython/test/test_rdict.py
Log:
manually merge the changes of the rdict-index-based branch (which itself has
the code from the more-gckinds branch, it seems). The work was mostly done by
mwh, I only adapted it to todays rdict.
The idea is to make rdict not use pointers to entries across function
boundaries too much, as this makes the life of a moving GC very hard. Instead,
the pair of (dict pointer, index) is used.
Modified: pypy/branch/rdict-index-based2/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/rdict-index-based2/pypy/rpython/lltypesystem/rdict.py (original)
+++ pypy/branch/rdict-index-based2/pypy/rpython/lltypesystem/rdict.py Tue Oct 2 20:45:00 2007
@@ -75,7 +75,7 @@
# compute the shape of the DICTENTRY structure
entryfields = []
- entrymeths = {
+ adtmeths = {
'must_clear_key': (isinstance(self.DICTKEY, lltype.Ptr)
and self.DICTKEY._needsgc()),
'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr)
@@ -98,23 +98,25 @@
s_value)
# * the state of the entry - trying to encode it as dummy objects
+ adtmeths['entry_has_f_everused'] = 0
+ adtmeths['entry_has_f_valid'] = 0
if nullkeymarker and dummykeyobj:
# all the state can be encoded in the key
- entrymeths['everused'] = ll_everused_from_key
- entrymeths['dummy_obj'] = dummykeyobj
- entrymeths['valid'] = ll_valid_from_key
- entrymeths['mark_deleted'] = ll_mark_deleted_in_key
+ adtmeths['entry_everused'] = ll_everused_from_key
+ adtmeths['dummy_obj'] = dummykeyobj
+ adtmeths['entry_valid'] = ll_valid_from_key
+ adtmeths['mark_entry_deleted'] = ll_mark_deleted_in_key
# the key is overwritten by 'dummy' when the entry is deleted
- entrymeths['must_clear_key'] = False
+ adtmeths['must_clear_key'] = False
elif nullvaluemarker and dummyvalueobj:
# all the state can be encoded in the value
- entrymeths['everused'] = ll_everused_from_value
- entrymeths['dummy_obj'] = dummyvalueobj
- entrymeths['valid'] = ll_valid_from_value
- entrymeths['mark_deleted'] = ll_mark_deleted_in_value
+ adtmeths['entry_everused'] = ll_everused_from_value
+ adtmeths['dummy_obj'] = dummyvalueobj
+ adtmeths['entry_valid'] = ll_valid_from_value
+ adtmeths['mark_entry_deleted'] = ll_mark_deleted_in_value
# value is overwritten by 'dummy' when entry is deleted
- entrymeths['must_clear_value'] = False
+ adtmeths['must_clear_value'] = False
else:
# we need a flag to know if the entry was ever used
@@ -122,25 +124,27 @@
# the key and value will be reset to NULL to clear their
# reference)
entryfields.append(("f_everused", lltype.Bool))
- entrymeths['everused'] = ll_everused_from_flag
+ adtmeths['entry_everused'] = ll_everused_from_flag
+ adtmeths['entry_has_f_everused'] = 1
# can we still rely on a dummy obj to mark deleted entries?
if dummykeyobj:
- entrymeths['dummy_obj'] = dummykeyobj
- entrymeths['valid'] = ll_valid_from_key
- entrymeths['mark_deleted'] = ll_mark_deleted_in_key
+ adtmeths['dummy_obj'] = dummykeyobj
+ adtmeths['entry_valid'] = ll_valid_from_key
+ adtmeths['mark_entry_deleted'] = ll_mark_deleted_in_key
# key is overwritten by 'dummy' when entry is deleted
- entrymeths['must_clear_key'] = False
+ adtmeths['must_clear_key'] = False
elif dummyvalueobj:
- entrymeths['dummy_obj'] = dummyvalueobj
- entrymeths['valid'] = ll_valid_from_value
- entrymeths['mark_deleted'] = ll_mark_deleted_in_value
+ adtmeths['dummy_obj'] = dummyvalueobj
+ adtmeths['entry_valid'] = ll_valid_from_value
+ adtmeths['mark_entry_deleted'] = ll_mark_deleted_in_value
# value is overwritten by 'dummy' when entry is deleted
- entrymeths['must_clear_value'] = False
+ adtmeths['must_clear_value'] = False
else:
entryfields.append(("f_valid", lltype.Bool))
- entrymeths['valid'] = ll_valid_from_flag
- entrymeths['mark_deleted'] = ll_mark_deleted_in_flag
+ adtmeths['entry_has_f_valid'] = 1
+ adtmeths['entry_valid'] = ll_valid_from_flag
+ adtmeths['mark_entry_deleted'] = ll_mark_deleted_in_flag
# * the value
entryfields.append(("value", self.DICTVALUE))
@@ -150,15 +154,19 @@
fasthashfn = None
else:
fasthashfn = self.key_repr.get_ll_fasthash_function()
+
+ adtmeths['entry_has_f_hash'] = 0
if fasthashfn is None:
entryfields.append(("f_hash", lltype.Signed))
- entrymeths['hash'] = ll_hash_from_cache
+ adtmeths['entry_has_f_hash'] = 1
+ # XXX entry_hash, maybe?
+ adtmeths['hash'] = ll_hash_from_cache
else:
- entrymeths['hash'] = ll_hash_recomputed
- entrymeths['fasthashfn'] = fasthashfn
+ adtmeths['hash'] = ll_hash_recomputed
+ adtmeths['fasthashfn'] = fasthashfn
# Build the lltype data structures
- self.DICTENTRY = lltype.Struct("dictentry", adtmeths=entrymeths,
+ self.DICTENTRY = lltype.Struct("dictentry",
*entryfields)
self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY)
fields = [ ("num_items", lltype.Signed),
@@ -168,13 +176,13 @@
self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr()
fields.extend([ ("fnkeyeq", self.r_rdict_eqfn.lowleveltype),
("fnkeyhash", self.r_rdict_hashfn.lowleveltype) ])
- adtmeths = {
+ adtmeths.update({
'keyhash': ll_keyhash_custom,
'keyeq': ll_keyeq_custom,
'r_rdict_eqfn': self.r_rdict_eqfn,
'r_rdict_hashfn': self.r_rdict_hashfn,
'paranoia': True,
- }
+ })
else:
# figure out which functions must be used to hash and compare
ll_keyhash = self.key_repr.get_ll_hash_function()
@@ -182,11 +190,11 @@
ll_keyhash = lltype.staticAdtMethod(ll_keyhash)
if ll_keyeq is not None:
ll_keyeq = lltype.staticAdtMethod(ll_keyeq)
- adtmeths = {
+ adtmeths.update({
'keyhash': ll_keyhash,
'keyeq': ll_keyeq,
'paranoia': False,
- }
+ })
adtmeths['KEY'] = self.DICTKEY
adtmeths['VALUE'] = self.DICTVALUE
self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
@@ -350,47 +358,47 @@
# be direct_call'ed from rtyped flow graphs, which means that they will
# get flowed and annotated, mostly with SomePtr.
-def ll_everused_from_flag(entry):
- return entry.f_everused
+def ll_everused_from_flag(d, i):
+ return d.entries[i].f_everused
+
+def ll_everused_from_key(d, i):
+ return bool(d.entries[i].key)
+
+def ll_everused_from_value(d, i):
+ return bool(d.entries[i].value)
+
+def ll_valid_from_flag(d, i):
+ return d.entries[i].f_valid
+
+def ll_mark_deleted_in_flag(d, i):
+ d.entries[i].f_valid = False
+
+def ll_valid_from_key(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ return d.entry_everused(i) and d.entries[i].key != dummy
+
+def ll_mark_deleted_in_key(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ d.entries[i].key = dummy
-def ll_everused_from_key(entry):
- return bool(entry.key)
+def ll_valid_from_value(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ return d.entry_everused(i) and d.entries[i].value != dummy
-def ll_everused_from_value(entry):
- return bool(entry.value)
+def ll_mark_deleted_in_value(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ d.entries[i].value = dummy
-def ll_valid_from_flag(entry):
- return entry.f_valid
-
-def ll_mark_deleted_in_flag(entry):
- entry.f_valid = False
-
-def ll_valid_from_key(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- return entry.everused() and entry.key != dummy
-
-def ll_mark_deleted_in_key(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- entry.key = dummy
-
-def ll_valid_from_value(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- return entry.everused() and entry.value != dummy
-
-def ll_mark_deleted_in_value(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- entry.value = dummy
-
-def ll_hash_from_cache(entry):
- return entry.f_hash
-
-def ll_hash_recomputed(entry):
- ENTRY = lltype.typeOf(entry).TO
- return ENTRY.fasthashfn(entry.key)
+def ll_hash_from_cache(d, i):
+ return d.entries[i].f_hash
+
+def ll_hash_recomputed(d, i):
+ DICT = lltype.typeOf(d).TO
+ return DICT.fasthashfn(d.entries[i].key)
def ll_keyhash_custom(d, key):
DICT = lltype.typeOf(d).TO
@@ -408,9 +416,9 @@
return bool(d) and d.num_items != 0
def ll_dict_getitem(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ if d.entry_valid(i):
+ return d.entries[i].value
else:
raise KeyError
ll_dict_getitem.oopspec = 'dict.getitem(d, key)'
@@ -418,20 +426,21 @@
def ll_dict_setitem(d, key, value):
hash = d.keyhash(key)
- entry = ll_dict_lookup(d, key, hash)
- everused = entry.everused()
- valid = entry.valid()
+ i = ll_dict_lookup(d, key, hash)
+ entry = d.entries[i]
+ everused = d.entry_everused(i)
+ valid = d.entry_valid(i)
# set up the new entry
- ENTRY = lltype.typeOf(entry).TO
+ DICT = lltype.typeOf(d).TO
entry.value = value
if valid:
return
entry.key = key
- if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash
- if hasattr(ENTRY, 'f_valid'): entry.f_valid = True
+ if DICT.entry_has_f_hash: entry.f_hash = hash
+ if DICT.entry_has_f_valid: entry.f_valid = True
d.num_items += 1
if not everused:
- if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
+ if DICT.entry_has_f_everused: entry.f_everused = True
d.num_pristine_entries -= 1
if d.num_pristine_entries <= len(d.entries) / 3:
ll_dict_resize(d)
@@ -443,35 +452,38 @@
# the dict contains no deleted entries. This routine has the advantage
# of never calling d.keyhash() and d.keyeq(), so it cannot call back
# to user code. ll_dict_insertclean() doesn't resize the dict, either.
- entry = ll_dict_lookup_clean(d, hash)
- ENTRY = lltype.typeOf(entry).TO
+ i = ll_dict_lookup(d, key, hash)
+ entry = d.entries[i]
+ DICT = lltype.typeOf(d).TO
entry.value = value
entry.key = key
- if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash
- if hasattr(ENTRY, 'f_valid'): entry.f_valid = True
- if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
+ if DICT.entry_has_f_hash: entry.f_hash = hash
+ if DICT.entry_has_f_valid: entry.f_valid = True
+ if DICT.entry_has_f_everused: entry.f_everused = True
d.num_items += 1
d.num_pristine_entries -= 1
def ll_dict_delitem(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- if not entry.valid():
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ if not d.entry_valid(i):
raise KeyError
- entry.mark_deleted()
+ d.mark_entry_deleted(i)
d.num_items -= 1
# clear the key and the value if they are GC pointers
- ENTRY = lltype.typeOf(entry).TO
- if ENTRY.must_clear_key:
+ DICT = lltype.typeOf(d).TO
+ entry = d.entries[i]
+ if DICT.must_clear_key:
key = entry.key # careful about destructor side effects:
# keep key alive until entry.value has also
# been zeroed (if it must be)
- entry.key = lltype.nullptr(ENTRY.key.TO)
- if ENTRY.must_clear_value:
- entry.value = lltype.nullptr(ENTRY.value.TO)
+ entry.key = lltype.nullptr(DICT.entries.TO.OF.key.TO)
+ if DICT.must_clear_value:
+ entry.value = lltype.nullptr(DICT.entries.TO.OF.value.TO)
num_entries = len(d.entries)
if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4:
ll_dict_resize(d)
+
def ll_dict_resize(d):
old_entries = d.entries
old_size = len(old_entries)
@@ -480,15 +492,34 @@
new_size = old_size * 2
while new_size > DICT_INITSIZE and d.num_items < new_size / 4:
new_size /= 2
- d.entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size, zero=True)
- d.num_items = 0
- d.num_pristine_entries = new_size
+ new_entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size, zero=True)
+ new_num_items = 0
+ new_num_pristine_entries = new_size
i = 0
while i < old_size:
entry = old_entries[i]
- if entry.valid():
- ll_dict_insertclean(d, entry.key, entry.value, entry.hash())
+ if d.entry_valid(i):
+ hash = d.hash(i)
+ # AAAAAAAAA XXX :-(
+ old_entries = d.entries
+ old_num_items = d.num_items
+ old_num_pristine_entries = d.num_pristine_entries
+ d.entries = new_entries
+ d.num_items = new_num_items
+ d.num_pristine_entries = new_num_pristine_entries
+
+ ll_dict_insertclean(d, entry.key, entry.value, hash)
+
+ new_entries = d.entries
+ new_num_items = d.num_items
+ new_num_pristine_entries = d.num_pristine_entries
+ d.entries = old_entries
+ d.num_items = old_num_items
+ d.num_pristine_entries = old_num_pristine_entries
i += 1
+ d.entries = new_entries
+ d.num_items = new_num_items
+ d.num_pristine_entries = new_num_pristine_entries
# ------- a port of CPython's dictobject.c's lookdict implementation -------
PERTURB_SHIFT = 5
@@ -500,26 +531,28 @@
i = r_uint(hash & mask)
# do the first try before any looping
entry = entries[i]
- if entry.valid():
+ found_freeslot = False
+ freeslot_index = r_uint(0)
+ if d.entry_valid(i):
checkingkey = entry.key
if checkingkey == key:
- return entry # found the entry
- if d.keyeq is not None and entry.hash() == hash:
+ return i # found the entry
+ if d.keyeq is not None and d.hash(i) == hash:
# correct hash, maybe the key is e.g. a different pointer to
# an equal object
found = d.keyeq(checkingkey, key)
if DICT.paranoia:
if (entries != d.entries or
- not entry.valid() or entry.key != checkingkey):
+ not d.entry_valid(i) or entry.key != checkingkey):
# the compare did major nasty stuff to the dict: start over
return ll_dict_lookup(d, key, hash)
if found:
- return entry # found the entry
- freeslot = lltype.nullptr(lltype.typeOf(entry).TO)
- elif entry.everused():
- freeslot = entry
+ return i # found the entry
+ elif d.entry_everused(i):
+ freeslot_index = i
+ found_freeslot = True
else:
- return entry # pristine entry -- lookup failed
+ return i # pristine entry -- lookup failed
# In the loop, a deleted entry (everused and not valid) is by far
# (factor of 100s) the least likely outcome, so test for that last.
@@ -527,26 +560,30 @@
while 1:
i = ((i << 2) + i + perturb + 1) & mask
entry = entries[i]
- if not entry.everused():
- return freeslot or entry
- elif entry.valid():
+ if not d.entry_everused(i):
+ if found_freeslot:
+ return freeslot_index
+ else:
+ return i
+ elif d.entry_valid(i):
checkingkey = entry.key
if checkingkey == key:
- return entry
- if d.keyeq is not None and entry.hash() == hash:
+ return i
+ if d.keyeq is not None and d.hash(i) == hash:
# correct hash, maybe the key is e.g. a different pointer to
# an equal object
found = d.keyeq(checkingkey, key)
if DICT.paranoia:
if (entries != d.entries or
- not entry.valid() or entry.key != checkingkey):
+ not d.entry_valid(i) or entry.key != checkingkey):
# the compare did major nasty stuff to the dict:
# start over
return ll_dict_lookup(d, key, hash)
if found:
- return entry # found the entry
- elif not freeslot:
- freeslot = entry
+ return i # found the entry
+ elif not found_freeslot:
+ freeslot_index = i
+ found_freeslot = True
perturb >>= PERTURB_SHIFT
def ll_dict_lookup_clean(d, hash):
@@ -556,13 +593,11 @@
entries = d.entries
mask = len(entries) - 1
i = r_uint(hash & mask)
- entry = entries[i]
perturb = r_uint(hash)
- while entry.everused():
+ while d.entry_everused(i):
i = ((i << 2) + i + perturb + 1) & mask
- entry = entries[i]
perturb >>= PERTURB_SHIFT
- return entry
+ return i
# ____________________________________________________________
#
@@ -638,8 +673,9 @@
entries_len = len(entries)
while index < entries_len:
entry = entries[index]
+ i = index
index = index + 1
- if entry.valid():
+ if dict.entry_valid(i):
iter.index = index
if RETURNTYPE is lltype.Void:
return None
@@ -660,16 +696,16 @@
# methods
def ll_get(dict, key, default):
- entry = ll_dict_lookup(dict, key, dict.keyhash(key))
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if dict.entry_valid(i):
+ return dict.entries[i].value
else:
return default
def ll_setdefault(dict, key, default):
- entry = ll_dict_lookup(dict, key, dict.keyhash(key))
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if dict.entry_valid(i):
+ return dict.entries[i].value
else:
ll_dict_setitem(dict, key, default)
return default
@@ -689,10 +725,10 @@
entry = dict.entries[i]
ENTRY = lltype.typeOf(entry).TO
d_entry.key = entry.key
- if hasattr(ENTRY, 'f_valid'): d_entry.f_valid = entry.f_valid
- if hasattr(ENTRY, 'f_everused'): d_entry.f_everused = entry.f_everused
+ if DICT.entry_has_f_valid : d_entry.f_valid = entry.f_valid
+ if DICT.entry_has_f_everused: d_entry.f_everused = entry.f_everused
d_entry.value = entry.value
- if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash
+ if DICT.entry_has_f_hash: d_entry.f_hash = entry.f_hash
i += 1
return d
@@ -709,8 +745,8 @@
d2len = len(entries)
i = 0
while i < d2len:
- entry = entries[i]
- if entry.valid():
+ if dic2.entry_valid(i):
+ entry = entries[i]
ll_dict_setitem(dic1, entry.key, entry.value)
i += 1
@@ -733,8 +769,8 @@
i = 0
p = 0
while i < dlen:
- entry = entries[i]
- if entry.valid():
+ if dic.entry_valid(i):
+ entry = entries[i]
ELEM = lltype.typeOf(items).TO.OF
if ELEM is not lltype.Void:
if func is dum_items:
@@ -751,7 +787,7 @@
return res
def ll_contains(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- return entry.valid()
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ return d.entry_valid(i)
ll_contains.oopspec = 'dict.contains(d, key)'
ll_contains.oopargcheck = lambda d, key: bool(d)
Modified: pypy/branch/rdict-index-based2/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/branch/rdict-index-based2/pypy/rpython/test/test_rdict.py (original)
+++ pypy/branch/rdict-index-based2/pypy/rpython/test/test_rdict.py Tue Oct 2 20:45:00 2007
@@ -548,7 +548,7 @@
res = self.interpret(func2, [ord(x), ord(y)])
for i in range(len(res.entries)):
- assert not (res.entries[i].everused() and not res.entries[i].valid())
+ assert not (res.entry_everused(i) and not res.entry_valid(i))
def func3(c0, c1, c2, c3, c4, c5, c6, c7):
d = {}
@@ -568,7 +568,7 @@
for i in range(rdict.DICT_INITSIZE)])
count_frees = 0
for i in range(len(res.entries)):
- if not res.entries[i].everused():
+ if not res.entry_everused(i):
count_frees += 1
assert count_frees >= 3
@@ -610,8 +610,8 @@
res = self.interpret(f, [])
assert res.item0 == True
DICT = lltype.typeOf(res.item1).TO
- assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None string keys
- assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strings have a dummy
+ assert not DICT.entry_has_f_everused# non-None string keys
+ assert not DICT.entry_has_f_valid # strings have a dummy
def test_opt_nullvaluemarker(self):
def f(n):
@@ -621,8 +621,8 @@
res = self.interpret(f, [-5])
assert res.item0 == 4
DICT = lltype.typeOf(res.item1).TO
- assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None str values
- assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strs have a dummy
+ assert not DICT.entry_has_f_everused# non-None string keys
+ assert not DICT.entry_has_f_valid # strings have a dummy
def test_opt_nonullmarker(self):
class A:
@@ -638,8 +638,8 @@
res = self.interpret(f, [-5])
assert res.item0 == -5441
DICT = lltype.typeOf(res.item1).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # can-be-None A instances
- assert not hasattr(DICT.entries.TO.OF, 'f_valid')# with a dummy A instance
+ assert DICT.entry_has_f_everused # can-be-None A instances
+ assert not DICT.entry_has_f_valid# with a dummy A instance
res = self.interpret(f, [6])
assert res.item0 == -5441
@@ -654,8 +654,8 @@
assert res.item0 == 1
assert res.item1 == 24
DICT = lltype.typeOf(res.item2).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero
- assert not hasattr(DICT.entries.TO.OF, 'f_valid')# nonneg int: dummy -1
+ assert DICT.entry_has_f_everused # all ints can be zero
+ assert not DICT.entry_has_f_valid# nonneg int: dummy -1
def test_opt_no_dummy(self):
def f(n):
@@ -667,8 +667,8 @@
assert res.item0 == 1
assert res.item1 == -24
DICT = lltype.typeOf(res.item2).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero
- assert hasattr(DICT.entries.TO.OF, 'f_valid') # no dummy available
+ assert DICT.entry_has_f_everused # all ints can be zero
+ assert DICT.entry_has_f_valid # no dummy available
def test_opt_multiple_identical_dicts(self):
def f(n):
More information about the Pypy-commit
mailing list