[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