SF Patch #1463867: Improved generator finalization to allow generators
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.
This commit is contained in:
parent
17de8ffc21
commit
2ba96610bf
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue