[pypy-svn] pypy default: use a weakref to store the class, else we might keep it alive forever
antocuni
commits-noreply at bitbucket.org
Tue Feb 15 14:51:33 CET 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch:
Changeset: r41952:260697f1c3e6
Date: 2011-02-15 14:00 +0100
http://bitbucket.org/pypy/pypy/changeset/260697f1c3e6/
Log: use a weakref to store the class, else we might keep it alive
forever
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -1,3 +1,4 @@
+import weakref
from pypy.rlib import jit, objectmodel, debug
from pypy.rlib.rarithmetic import intmask, r_uint
@@ -162,7 +163,15 @@
def __init__(self, space, w_cls):
AbstractAttribute.__init__(self, space, self)
- self.w_cls = w_cls
+ if w_cls is None:
+ self.w_cls_wref = None
+ else:
+ self.w_cls_wref = weakref.ref(w_cls)
+
+ def get_w_cls(self):
+ if self.w_cls_wref is None:
+ return None
+ return self.w_cls_wref()
def _read_terminator(self, obj, selector):
return None
@@ -396,7 +405,7 @@
assert flag
def getclass(self, space):
- return self._get_mapdict_map().terminator.w_cls
+ return self._get_mapdict_map().terminator.get_w_cls()
def setclass(self, space, w_cls):
new_obj = self._get_mapdict_map().set_terminator(self, w_cls.terminator)
@@ -685,7 +694,10 @@
def is_valid_for_map(self, map):
if map is self.map:
- version_tag = map.terminator.w_cls.version_tag()
+ w_cls = map.terminator.get_w_cls()
+ if w_cls is None: # probably a dead weakref
+ return False
+ version_tag = w_cls.version_tag()
if version_tag is self.version_tag:
# everything matches, it's incredibly fast
if map.space.config.objspace.std.withmethodcachecounter:
@@ -730,7 +742,7 @@
space = pycode.space
w_name = pycode.co_names_w[nameindex]
if map is not None:
- w_type = map.terminator.w_cls
+ w_type = map.terminator.get_w_cls()
w_descr = w_type.getattribute_if_not_from_object()
if w_descr is not None:
return space._handle_getattribute(w_descr, w_obj, w_name)
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -24,12 +24,14 @@
hasdict = False
def test_plain_attribute():
- w_cls = "class"
+ class FakeClass(object):
+ pass
+ w_cls = FakeClass
aa = PlainAttribute(("b", DICT),
PlainAttribute(("a", DICT),
Terminator(space, w_cls)))
assert aa.space is space
- assert aa.terminator.w_cls is w_cls
+ assert aa.terminator.get_w_cls() is w_cls
assert aa.get_terminator() is aa.terminator
obj = Object()
@@ -866,6 +868,23 @@
res = self.check(f, 'm')
assert res == (0, 2, 1)
+ def test_dont_keep_class_alive(self):
+ import weakref
+ import gc
+ def f():
+ class C(object):
+ def m(self):
+ pass
+ r = weakref.ref(C)
+ # Trigger cache.
+ C().m()
+ del C
+ gc.collect(); gc.collect(); gc.collect()
+ assert r() is None
+ return 42
+ f()
+
+
class AppTestGlobalCaching(AppTestWithMapDict):
def setup_class(cls):
cls.space = gettestobjspace(
More information about the Pypy-commit
mailing list