[pypy-svn] r79300 - in pypy/branch/jit-free/pypy: interpreter module/_pickle_support
arigo at codespeak.net
arigo at codespeak.net
Sat Nov 20 15:14:01 CET 2010
Author: arigo
Date: Sat Nov 20 15:14:00 2010
New Revision: 79300
Modified:
pypy/branch/jit-free/pypy/interpreter/baseobjspace.py
pypy/branch/jit-free/pypy/interpreter/generator.py
pypy/branch/jit-free/pypy/module/_pickle_support/maker.py
Log:
Try to make generators more friendly towards the GC. In the common case
where the generator is run to completion, set 'self.frame' to None
(as in CPython actually). Should lower the risks of seeing chains of
objects with a __del__.
Modified: pypy/branch/jit-free/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/jit-free/pypy/interpreter/baseobjspace.py (original)
+++ pypy/branch/jit-free/pypy/interpreter/baseobjspace.py Sat Nov 20 15:14:00 2010
@@ -147,7 +147,7 @@
__already_enqueued_for_destruction = False
- def _enqueue_for_destruction(self, space):
+ def _enqueue_for_destruction(self, space, call_user_del=True):
"""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.
@@ -160,7 +160,8 @@
return
self.__already_enqueued_for_destruction = True
self.clear_all_weakrefs()
- space.user_del_action.register_dying_object(self)
+ if call_user_del:
+ space.user_del_action.register_dying_object(self)
def _call_builtin_destructor(self):
pass # method overridden in typedef.py
Modified: pypy/branch/jit-free/pypy/interpreter/generator.py
==============================================================================
--- pypy/branch/jit-free/pypy/interpreter/generator.py (original)
+++ pypy/branch/jit-free/pypy/interpreter/generator.py Sat Nov 20 15:14:00 2010
@@ -10,7 +10,7 @@
def __init__(self, frame):
self.space = frame.space
- self.frame = frame
+ self.frame = frame # turned into None when frame_finished_execution
self.running = False
def descr__reduce__(self, space):
@@ -19,9 +19,13 @@
mod = space.interp_w(MixedModule, w_mod)
new_inst = mod.get('generator_new')
w = space.wrap
+ if self.frame:
+ w_frame = w(self.frame)
+ else:
+ w_frame = space.w_None
tup = [
- w(self.frame),
+ w_frame,
w(self.running),
]
@@ -41,7 +45,8 @@
if self.running:
raise OperationError(space.w_ValueError,
space.wrap('generator already executing'))
- if self.frame.frame_finished_execution:
+ frame = self.frame
+ if frame is None:
# xxx a bit ad-hoc, but we don't want to go inside
# execute_generator_frame() if the frame is actually finished
if operr is None:
@@ -49,7 +54,7 @@
raise operr
# XXX it's not clear that last_instr should be promoted at all
# but as long as it is necessary for call_assembler, let's do it early
- last_instr = jit.hint(self.frame.last_instr, promote=True)
+ last_instr = jit.hint(frame.last_instr, promote=True)
if last_instr == -1:
if w_arg and not space.is_w(w_arg, space.w_None):
msg = "can't send non-None value to a just-started generator"
@@ -60,18 +65,19 @@
self.running = True
try:
try:
- w_result = self.frame.execute_generator_frame(w_arg, operr)
+ w_result = frame.execute_generator_frame(w_arg, operr)
except OperationError:
# errors finish a frame
- self.frame.frame_finished_execution = True
+ self.frame = None
raise
# if the frame is now marked as finished, it was RETURNed from
- if self.frame.frame_finished_execution:
+ if frame.frame_finished_execution:
+ self.frame = None
raise OperationError(space.w_StopIteration, space.w_None)
else:
return w_result # YIELDed
finally:
- self.frame.f_backref = jit.vref_None
+ frame.f_backref = jit.vref_None
self.running = False
def descr_throw(self, w_type, w_val=None, w_tb=None):
@@ -115,7 +121,7 @@
raise OperationError(space.w_RuntimeError, space.wrap(msg))
def descr_gi_frame(space, self):
- if not self.frame.frame_finished_execution:
+ if self.frame is not None and not self.frame.frame_finished_execution:
return self.frame
else:
return space.w_None
@@ -125,15 +131,17 @@
applevel __del__, which is called at a safe point after the
interp-level __del__ enqueued the object for destruction
"""
- # Only bother raising an exception if the frame is still not
- # finished and finally or except blocks are present.
- if not self.frame.frame_finished_execution:
+ self.descr_close()
+
+ def __del__(self):
+ # Only bother enqueuing self to raise an exception if the frame is
+ # still not finished and finally or except blocks are present.
+ must_call_close = False
+ if self.frame is not None:
block = self.frame.lastblock
while block is not None:
if not isinstance(block, LoopBlock):
- self.descr_close()
- return
+ must_call_close = True
+ break
block = block.previous
-
- def __del__(self):
- self._enqueue_for_destruction(self.space)
+ self._enqueue_for_destruction(self.space, must_call_close)
Modified: pypy/branch/jit-free/pypy/module/_pickle_support/maker.py
==============================================================================
--- pypy/branch/jit-free/pypy/module/_pickle_support/maker.py (original)
+++ pypy/branch/jit-free/pypy/module/_pickle_support/maker.py Sat Nov 20 15:14:00 2010
@@ -67,11 +67,12 @@
return space.wrap(tb)
traceback_new.unwrap_spec = [ObjSpace]
-def generator_new(space, frame, running):
+def generator_new(space, w_frame, running):
+ frame = space.interp_w(PyFrame, w_frame, can_be_None=True)
new_generator = GeneratorIterator(frame)
new_generator.running = running
return space.wrap(new_generator)
-generator_new.unwrap_spec = [ObjSpace, PyFrame, int]
+generator_new.unwrap_spec = [ObjSpace, W_Root, int]
def xrangeiter_new(space, current, remaining, step):
from pypy.module.__builtin__.functional import W_XRangeIterator
More information about the Pypy-commit
mailing list