mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
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.
This commit is contained in:
parent
2942131dac
commit
2b13ce8317
1 changed files with 27 additions and 14 deletions
|
@ -138,6 +138,7 @@ gen_dealloc(genobject *gen)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
gen_iternext(genobject *gen)
|
gen_iternext(genobject *gen)
|
||||||
{
|
{
|
||||||
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
PyFrameObject *f = gen->frame;
|
PyFrameObject *f = gen->frame;
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
|
@ -149,14 +150,23 @@ gen_iternext(genobject *gen)
|
||||||
if (f->f_stackbottom == NULL) {
|
if (f->f_stackbottom == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
gen->running = 1;
|
||||||
result = eval_frame(f);
|
result = eval_frame(f);
|
||||||
gen->running = 0;
|
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
|
/* Don't keep the reference to f_back any longer than necessary. It
|
||||||
that eval_frame sets f->f_back without bumping its refcount: we
|
* may keep a chain of frames alive or it could create a reference
|
||||||
never had a fully legit reference to it). */
|
* cycle. */
|
||||||
|
Py_DECREF(f->f_back);
|
||||||
f->f_back = NULL;
|
f->f_back = NULL;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,9 +578,7 @@ eval_frame(PyFrameObject *f)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->f_back = tstate->frame;
|
|
||||||
tstate->frame = f;
|
tstate->frame = f;
|
||||||
|
|
||||||
co = f->f_code;
|
co = f->f_code;
|
||||||
fastlocals = f->f_localsplus;
|
fastlocals = f->f_localsplus;
|
||||||
freevars = f->f_localsplus + f->f_nlocals;
|
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) {
|
if (co->co_flags & CO_GENERATOR) {
|
||||||
/* create a new generator that owns the ready to run frame
|
/* Don't need to keep the reference to f_back, it will be set
|
||||||
* and return that as the value */
|
* 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);
|
return gen_new(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue