Author: Armin Rigo <[email protected]>
Branch:
Changeset: r55003:ea21f0cc18c3
Date: 2012-05-10 08:43 +0200
http://bitbucket.org/pypy/pypy/changeset/ea21f0cc18c3/
Log: Use here too an AbstractShrinkList instead of this ever-growing
list. Some refactorings are needed because we cannot any more cache
by index some entries of the list.
diff --git a/pypy/module/_weakref/interp__weakref.py
b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -4,25 +4,50 @@
from pypy.interpreter.gateway import interp2app, ObjSpace
from pypy.interpreter.typedef import TypeDef
from pypy.rlib import jit
+from pypy.rlib.rshrinklist import AbstractShrinkList
+from pypy.rlib.objectmodel import specialize
import weakref
+class WRefShrinkList(AbstractShrinkList):
+ def must_keep(self, wref):
+ return wref() is not None
+
+
class WeakrefLifeline(W_Root):
- cached_weakref_index = -1
- cached_proxy_index = -1
+ cached_weakref = None
+ cached_proxy = None
+ other_refs_weak = None
def __init__(self, space):
self.space = space
- self.refs_weak = []
+
+ def append_wref_to(self, w_ref):
+ if self.other_refs_weak is None:
+ self.other_refs_weak = WRefShrinkList()
+ self.other_refs_weak.append(weakref.ref(w_ref))
+
+ @specialize.arg(1)
+ def traverse(self, callback, arg=None):
+ if self.cached_weakref is not None:
+ arg = callback(self, self.cached_weakref, arg)
+ if self.cached_proxy is not None:
+ arg = callback(self, self.cached_proxy, arg)
+ if self.other_refs_weak is not None:
+ for ref_w_ref in self.other_refs_weak.items():
+ arg = callback(self, ref_w_ref, arg)
+ return arg
+
+ def _clear_wref(self, wref, _):
+ w_ref = wref()
+ if w_ref is not None:
+ w_ref.clear()
def clear_all_weakrefs(self):
"""Clear all weakrefs. This is called when an app-level object has
a __del__, just before the app-level __del__ method is called.
"""
- for ref_w_ref in self.refs_weak:
- w_ref = ref_w_ref()
- if w_ref is not None:
- w_ref.clear()
+ self.traverse(WeakrefLifeline._clear_wref)
# Note that for no particular reason other than convenience,
# weakref callbacks are not invoked eagerly here. They are
# invoked by self.__del__() anyway.
@@ -30,49 +55,46 @@
def get_or_make_weakref(self, w_subtype, w_obj):
space = self.space
w_weakreftype = space.gettypeobject(W_Weakref.typedef)
- is_weakreftype = space.is_w(w_weakreftype, w_subtype)
- if is_weakreftype and self.cached_weakref_index >= 0:
- w_cached = self.refs_weak[self.cached_weakref_index]()
- if w_cached is not None:
- return w_cached
- else:
- self.cached_weakref_index = -1
- w_ref = space.allocate_instance(W_Weakref, w_subtype)
- index = len(self.refs_weak)
- W_Weakref.__init__(w_ref, space, w_obj, None)
- self.refs_weak.append(weakref.ref(w_ref))
- if is_weakreftype:
- self.cached_weakref_index = index
+ #
+ if space.is_w(w_weakreftype, w_subtype):
+ if self.cached_weakref is not None:
+ w_cached = self.cached_weakref()
+ if w_cached is not None:
+ return w_cached
+ w_ref = W_Weakref(space, w_obj, None)
+ self.cached_weakref = weakref.ref(w_ref)
+ else:
+ # subclass: cannot cache
+ w_ref = space.allocate_instance(W_Weakref, w_subtype)
+ W_Weakref.__init__(w_ref, space, w_obj, None)
+ self.append_wref_to(w_ref)
return w_ref
def get_or_make_proxy(self, w_obj):
space = self.space
- if self.cached_proxy_index >= 0:
- w_cached = self.refs_weak[self.cached_proxy_index]()
+ if self.cached_proxy is not None:
+ w_cached = self.cached_proxy()
if w_cached is not None:
return w_cached
- else:
- self.cached_proxy_index = -1
- index = len(self.refs_weak)
if space.is_true(space.callable(w_obj)):
w_proxy = W_CallableProxy(space, w_obj, None)
else:
w_proxy = W_Proxy(space, w_obj, None)
- self.refs_weak.append(weakref.ref(w_proxy))
- self.cached_proxy_index = index
+ self.cached_proxy = weakref.ref(w_proxy)
return w_proxy
def get_any_weakref(self, space):
- if self.cached_weakref_index != -1:
- w_ref = self.refs_weak[self.cached_weakref_index]()
+ if self.cached_weakref is not None:
+ w_ref = self.cached_weakref()
if w_ref is not None:
return w_ref
- w_weakreftype = space.gettypeobject(W_Weakref.typedef)
- for i in range(len(self.refs_weak)):
- w_ref = self.refs_weak[i]()
- if (w_ref is not None and
- space.is_true(space.isinstance(w_ref, w_weakreftype))):
- return w_ref
+ if self.other_refs_weak is not None:
+ w_weakreftype = space.gettypeobject(W_Weakref.typedef)
+ for wref in self.other_refs_weak.items():
+ w_ref = wref()
+ if (w_ref is not None and
+ space.is_true(space.isinstance(w_ref, w_weakreftype))):
+ return w_ref
return space.w_None
@@ -80,10 +102,10 @@
def __init__(self, space, oldlifeline=None):
self.space = space
- if oldlifeline is None:
- self.refs_weak = []
- else:
- self.refs_weak = oldlifeline.refs_weak
+ if oldlifeline is not None:
+ self.cached_weakref = oldlifeline.cached_weakref
+ self.cached_proxy = oldlifeline.cached_proxy
+ self.other_refs_weak = oldlifeline.other_refs_weak
def __del__(self):
"""This runs when the interp-level object goes away, and allows
@@ -91,8 +113,11 @@
callbacks even if there is no __del__ method on the interp-level
W_Root subclass implementing the object.
"""
- for i in range(len(self.refs_weak) - 1, -1, -1):
- w_ref = self.refs_weak[i]()
+ if self.other_refs_weak is None:
+ return
+ items = self.other_refs_weak.items()
+ for i in range(len(items)-1, -1, -1):
+ w_ref = items[i]()
if w_ref is not None and w_ref.w_callable is not None:
w_ref.enqueue_for_destruction(self.space,
W_WeakrefBase.activate_callback,
@@ -102,7 +127,7 @@
space = self.space
w_ref = space.allocate_instance(W_Weakref, w_subtype)
W_Weakref.__init__(w_ref, space, w_obj, w_callable)
- self.refs_weak.append(weakref.ref(w_ref))
+ self.append_wref_to(w_ref)
return w_ref
def make_proxy_with_callback(self, w_obj, w_callable):
@@ -111,7 +136,7 @@
w_proxy = W_CallableProxy(space, w_obj, w_callable)
else:
w_proxy = W_Proxy(space, w_obj, w_callable)
- self.refs_weak.append(weakref.ref(w_proxy))
+ self.append_wref_to(w_proxy)
return w_proxy
# ____________________________________________________________
@@ -247,30 +272,33 @@
)
+def _weakref_count(lifeline, wref, count):
+ if wref() is not None:
+ count += 1
+ return count
+
def getweakrefcount(space, w_obj):
"""Return the number of weak references to 'obj'."""
lifeline = w_obj.getweakref()
if lifeline is None:
return space.wrap(0)
else:
- result = 0
- for i in range(len(lifeline.refs_weak)):
- if lifeline.refs_weak[i]() is not None:
- result += 1
+ result = lifeline.traverse(_weakref_count, 0)
return space.wrap(result)
+def _get_weakrefs(lifeline, wref, result):
+ w_ref = wref()
+ if w_ref is not None:
+ result.append(w_ref)
+ return result
+
def getweakrefs(space, w_obj):
"""Return a list of all weak reference objects that point to 'obj'."""
+ result = []
lifeline = w_obj.getweakref()
- if lifeline is None:
- return space.newlist([])
- else:
- result = []
- for i in range(len(lifeline.refs_weak)):
- w_ref = lifeline.refs_weak[i]()
- if w_ref is not None:
- result.append(w_ref)
- return space.newlist(result)
+ if lifeline is not None:
+ lifeline.traverse(_get_weakrefs, result)
+ return space.newlist(result)
#_________________________________________________________________
# Proxy
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit