[pypy-svn] r57205 - in pypy/dist/pypy: interpreter module/__builtin__ module/gc/test
arigo at codespeak.net
arigo at codespeak.net
Tue Aug 12 13:52:28 CEST 2008
Author: arigo
Date: Tue Aug 12 13:52:28 2008
New Revision: 57205
Modified:
pypy/dist/pypy/interpreter/baseobjspace.py
pypy/dist/pypy/interpreter/typedef.py
pypy/dist/pypy/module/__builtin__/interp_classobj.py
pypy/dist/pypy/module/gc/test/test_gc.py
Log:
Fix the __del__ handling of old-style instances
to match the __del__ handling of new-style instances,
in particular regarding the usage of a queue to avoid
crashes if the app-level method is called immediately.
Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py (original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py Tue Aug 12 13:52:28 2008
@@ -138,6 +138,23 @@
self.setweakref(lifeline.space, None)
lifeline.clear_all_weakrefs()
+ __already_enqueued_for_destruction = False
+
+ def _enqueue_for_destruction(self, space):
+ """Put the object in the destructor queue of the space.
+ At a later, safe point in time, UserDelAction will use
+ space.userdel() to call the object's app-level __del__ method.
+ """
+ # this function always resurect the object, so when
+ # running on top of CPython we must manually ensure that
+ # we enqueue it only once
+ if not we_are_translated():
+ if self.__already_enqueued_for_destruction:
+ return
+ self.__already_enqueued_for_destruction = True
+ self.clear_all_weakrefs()
+ space.user_del_action.register_dying_object(self)
+
def _call_builtin_destructor(self):
pass # method overridden in typedef.py
Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py (original)
+++ pypy/dist/pypy/interpreter/typedef.py Tue Aug 12 13:52:28 2008
@@ -9,7 +9,7 @@
DescrMismatch
from pypy.interpreter.error import OperationError
from pypy.tool.sourcetools import compile2, func_with_new_name
-from pypy.rlib.objectmodel import instantiate, we_are_translated
+from pypy.rlib.objectmodel import instantiate
from pypy.rlib.rarithmetic import intmask
class TypeDef:
@@ -248,17 +248,8 @@
if "del" in features:
class Proto(object):
- _del_was_called = False
def __del__(self):
- # the logic below always resurect the objects, so when
- # running on top of CPython we must manually ensure that
- # we do it only once
- if not we_are_translated():
- if self._del_was_called:
- return
- self._del_was_called = True
- self.clear_all_weakrefs()
- self.space.user_del_action.register_dying_object(self)
+ self._enqueue_for_destruction(self.space)
# if the base class needs its own interp-level __del__,
# we override the _call_builtin_destructor() method to invoke it
# after the app-level destructor.
Modified: pypy/dist/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/interp_classobj.py (original)
+++ pypy/dist/pypy/module/__builtin__/interp_classobj.py Tue Aug 12 13:52:28 2008
@@ -630,6 +630,13 @@
space.wrap("instance has no next() method"))
return space.call_function(w_func)
+ def descr_del(self, space):
+ # Note that this is called from executioncontext.UserDelAction
+ # via the space.userdel() method.
+ w_func = self.getattr(space, space.wrap('__del__'), False)
+ if w_func is not None:
+ space.call_function(w_func)
+
rawdict = {}
# unary operations
@@ -719,20 +726,11 @@
next = interp2app(W_InstanceObject.descr_next,
unwrap_spec=['self', ObjSpace]),
__weakref__ = make_weakref_descr(W_InstanceObject),
+ __del__ = interp2app(W_InstanceObject.descr_del,
+ unwrap_spec=['self', ObjSpace]),
**rawdict
)
class W_InstanceObjectWithDel(W_InstanceObject):
def __del__(self):
- self.clear_all_weakrefs()
- try:
- self.descr_del()
- except OperationError, e:
- e.write_unraisable(self.space, 'method __del__ of ', self)
- e.clear(self.space) # break up reference cycles
-
- def descr_del(self):
- space = self.space
- w_func = self.getattr(space, space.wrap('__del__'), False)
- if w_func is not None:
- space.call_function(w_func)
+ self._enqueue_for_destruction(self.space)
Modified: pypy/dist/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/dist/pypy/module/gc/test/test_gc.py (original)
+++ pypy/dist/pypy/module/gc/test/test_gc.py Tue Aug 12 13:52:28 2008
@@ -5,6 +5,7 @@
def test_disable_finalizers(self):
import gc
+
class X(object):
created = 0
deleted = 0
@@ -12,18 +13,31 @@
X.created += 1
def __del__(self):
X.deleted += 1
+
+ class OldX:
+ created = 0
+ deleted = 0
+ def __init__(self):
+ OldX.created += 1
+ def __del__(self):
+ OldX.deleted += 1
+
def runtest(should_be_enabled):
+ runtest1(should_be_enabled, X)
+ runtest1(should_be_enabled, OldX)
+
+ def runtest1(should_be_enabled, Cls):
gc.collect()
if should_be_enabled:
- assert X.deleted == X.created
+ assert Cls.deleted == Cls.created
else:
- old_deleted = X.deleted
- X(); X(); X()
+ old_deleted = Cls.deleted
+ Cls(); Cls(); Cls()
gc.collect()
if should_be_enabled:
- assert X.deleted == X.created
+ assert Cls.deleted == Cls.created
else:
- assert X.deleted == old_deleted
+ assert Cls.deleted == old_deleted
runtest(True)
gc.disable_finalizers()
More information about the Pypy-commit
mailing list