summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-06-21 02:41:10 (GMT)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-06-21 02:41:10 (GMT)
commit2b13ce831795f6f0304c157a31909ac2ce5d5ccb (patch)
tree487cc560419a346c118bd870f81d7402fe7b6847 /Python/ceval.c
parent2942131dac32b197da5a604906c322b971234a55 (diff)
downloadcpython-2b13ce831795f6f0304c157a31909ac2ce5d5ccb.zip
cpython-2b13ce831795f6f0304c157a31909ac2ce5d5ccb.tar.gz
cpython-2b13ce831795f6f0304c157a31909ac2ce5d5ccb.tar.bz2
Try to avoid creating reference cycles involving generators. Only keep a
reference to f_back when its really needed. Do a little whitespace normalization as well. This whole file is a big war between tabs and spaces but now is probably not the time to reindent everything.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index ea5c537..a71d48f 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -138,6 +138,7 @@ gen_dealloc(genobject *gen)
static PyObject *
gen_iternext(genobject *gen)
{
+ PyThreadState *tstate = PyThreadState_GET();
PyFrameObject *f = gen->frame;
PyObject *result;
@@ -149,15 +150,24 @@ gen_iternext(genobject *gen)
if (f->f_stackbottom == NULL) {
return NULL;
}
- gen->running = 1;
+
+ /* Generators always return to their most recent caller, not
+ * necessarily their creator. */
+ Py_INCREF(tstate->frame);
+ assert(f->f_back == NULL);
+ f->f_back = tstate->frame;
+
+ gen->running = 1;
result = eval_frame(f);
- gen->running = 0;
- /* The connection between this frame and its parent is over now, so
- must NULL out f_back lest it get decref'ed when gen dies (note
- that eval_frame sets f->f_back without bumping its refcount: we
- never had a fully legit reference to it). */
+ gen->running = 0;
+
+ /* Don't keep the reference to f_back any longer than necessary. It
+ * may keep a chain of frames alive or it could create a reference
+ * cycle. */
+ Py_DECREF(f->f_back);
f->f_back = NULL;
- return result;
+
+ return result;
}
static PyObject *
@@ -168,12 +178,12 @@ gen_next(genobject *gen, PyObject *args)
if (!PyArg_ParseTuple(args, ":next"))
return NULL;
- result = gen_iternext(gen);
+ result = gen_iternext(gen);
- if (result == NULL && !PyErr_Occurred()) {
+ if (result == NULL && !PyErr_Occurred()) {
PyErr_SetObject(PyExc_StopIteration, Py_None);
return NULL;
- }
+ }
return result;
}
@@ -568,9 +578,7 @@ eval_frame(PyFrameObject *f)
return NULL;
}
- f->f_back = tstate->frame;
tstate->frame = f;
-
co = f->f_code;
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + f->f_nlocals;
@@ -2482,8 +2490,13 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
}
if (co->co_flags & CO_GENERATOR) {
- /* create a new generator that owns the ready to run frame
- * and return that as the value */
+ /* Don't need to keep the reference to f_back, it will be set
+ * when the generator is resumed. */
+ Py_DECREF(f->f_back);
+ f->f_back = NULL;
+
+ /* Create a new generator that owns the ready to run frame
+ * and return that as the value. */
return gen_new(f);
}