Commits

Armin Rigo committed 5d63ae1

Tweaks. Unsure why but it seems that test_zll_random ends up with
two differently-typed arrays at the same address --- it might be
because of casts. The _subarray caching fails in this case, by
confusing the types of the subarrays.

Comments (0)

Files changed (1)

pypy/rpython/lltypesystem/lltype.py

 class _subarray(_parentable):     # only for direct_fieldptr()
                                   # and direct_arrayitems()
     _kind = "subarray"
-    _cache = weakref.WeakKeyDictionary()  # parentarray -> {subarrays}
+    _cache = {}  # TYPE -> weak{ parentarray -> {subarrays} }
 
     def __init__(self, TYPE, parent, baseoffset_or_fieldname):
         _parentable.__init__(self, TYPE)
 
     def _makeptr(parent, baseoffset_or_fieldname, solid=False):
         try:
-            cache = _subarray._cache.setdefault(parent, {})
+            d = _subarray._cache[parent._TYPE]
+        except KeyError:
+            d = _subarray._cache[parent._TYPE] = weakref.WeakKeyDictionary()
+        try:
+            cache = d.setdefault(parent, {})
         except RuntimeError:    # pointer comparison with a freed structure
             _subarray._cleanup_cache()
-            cache = _subarray._cache.setdefault(parent, {})    # try again
+            cache = d.setdefault(parent, {})    # try again
         try:
             subarray = cache[baseoffset_or_fieldname]
         except KeyError:
         raise NotImplementedError('_subarray._getid()')
 
     def _cleanup_cache():
-        newcache = weakref.WeakKeyDictionary()
-        for key, value in _subarray._cache.items():
-            try:
-                if not key._was_freed():
-                    newcache[key] = value
-            except RuntimeError:
-                pass    # ignore "accessing subxxx, but already gc-ed parent"
-        _subarray._cache = newcache
+        for T, d in _subarray._cache.items():
+            newcache = weakref.WeakKeyDictionary()
+            for key, value in d.items():
+                try:
+                    if not key._was_freed():
+                        newcache[key] = value
+                except RuntimeError:
+                    pass    # ignore "accessing subxxx, but already gc-ed parent"
+            if newcache:
+                _subarray._cache[T] = newcache
+            else:
+                del _subarray._cache[T]
     _cleanup_cache = staticmethod(_cleanup_cache)