]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
SF Patch #1463867: Improved generator finalization to allow generators
authorPhillip J. Eby <pje@telecommunity.com>
Mon, 10 Apr 2006 17:51:05 +0000 (17:51 +0000)
committerPhillip J. Eby <pje@telecommunity.com>
Mon, 10 Apr 2006 17:51:05 +0000 (17:51 +0000)
that are suspended outside of any try/except/finally blocks to be
garbage collected even if they are part of a cycle.  Generators that
suspend inside of an active try/except or try/finally block (including
those created by a ``with`` statement) are still not GC-able if they
are part of a cycle, however.

Include/genobject.h
Modules/gcmodule.c
Objects/genobject.c
Python/ceval.c

index f4226ede420aa221ff3e3da0f339d4f0ed4d4b09..1ecd7ad773c46107dacf1264e4674ae210c7ca7c 100644 (file)
@@ -28,6 +28,7 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
 #define PyGen_CheckExact(op) ((op)->ob_type == &PyGen_Type)
 
 PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
+PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
 
 #ifdef __cplusplus
 }
index a8976b3ce7a52693b43cf23eee3c24b0f200a207..5bf95b9185a0342fd86bd8190b0c979177f3cc33 100644 (file)
@@ -413,8 +413,12 @@ has_finalizer(PyObject *op)
                assert(delstr != NULL);
                return _PyInstance_Lookup(op, delstr) != NULL;
        }
-       else
+       else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE))
                return op->ob_type->tp_del != NULL;
+       else if (PyGen_CheckExact(op))
+               return PyGen_NeedsFinalizing((PyGenObject *)op);
+       else
+               return 0;
 }
 
 /* Move the objects in unreachable with __del__ methods into `finalizers`.
index e7b8f8754a1f93af1564b6a7dabb75031405a04d..a3eae6a6b989676528f8867e016f976ddd277981 100644 (file)
@@ -5,6 +5,7 @@
 #include "genobject.h"
 #include "ceval.h"
 #include "structmember.h"
+#include "opcode.h"
 
 static int
 gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
@@ -358,3 +359,22 @@ PyGen_New(PyFrameObject *f)
        _PyObject_GC_TRACK(gen);
        return (PyObject *)gen;
 }
+
+int
+PyGen_NeedsFinalizing(PyGenObject *gen)
+{
+       int i;
+       PyFrameObject *f = gen->gi_frame;
+
+       if ((PyObject *)f == Py_None || f->f_stacktop==NULL || f->f_iblock<=0)
+               return 0; /* no frame or no blockstack == no finalization */
+
+       for (i=f->f_iblock; i>=0; i--) {
+               if (f->f_blockstack[i].b_type != SETUP_LOOP)
+                       /* any block type besides a loop requires cleanup */
+                       return 1;
+       }
+
+       /* No blocks except loops, it's safe to skip finalization */
+       return 0;
+}
index cc1eb97fe0b1a492b33533a6fb4e3ee63c37cdfd..6302ede18f05dc3901f2ebafbd738d72ed2b732f 100644 (file)
@@ -2179,6 +2179,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
                case SETUP_LOOP:
                case SETUP_EXCEPT:
                case SETUP_FINALLY:
+                       /* NOTE: If you add any new block-setup opcodes that are not try/except/finally
+                          handlers, you may need to update the PyGen_NeedsFinalizing() function. */
+
                        PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
                                           STACK_LEVEL());
                        continue;