mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
bpo-47045: Remove f_state
field (GH-31963)
* Remove the f_state field from _PyInterpreterFrame * Make ownership of the frame explicit, replacing the is_generator field with an owner field.
This commit is contained in:
parent
88872a29f1
commit
49daf6dba8
9 changed files with 260 additions and 220 deletions
|
@ -35,9 +35,10 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
|
|||
Py_VISIT(gen->gi_code);
|
||||
Py_VISIT(gen->gi_name);
|
||||
Py_VISIT(gen->gi_qualname);
|
||||
if (gen->gi_frame_valid) {
|
||||
if (gen->gi_frame_state < FRAME_CLEARED) {
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe);
|
||||
assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0);
|
||||
assert(frame->frame_obj == NULL ||
|
||||
frame->frame_obj->f_frame->owner == FRAME_OWNED_BY_GENERATOR);
|
||||
int err = _PyFrame_Traverse(frame, visit, arg);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -55,7 +56,7 @@ _PyGen_Finalize(PyObject *self)
|
|||
PyObject *res = NULL;
|
||||
PyObject *error_type, *error_value, *error_traceback;
|
||||
|
||||
if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted((_PyInterpreterFrame *)gen->gi_iframe)) {
|
||||
if (gen->gi_frame_state >= FRAME_COMPLETED) {
|
||||
/* Generator isn't paused, so no need to close */
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ _PyGen_Finalize(PyObject *self)
|
|||
issue a RuntimeWarning. */
|
||||
if (gen->gi_code != NULL &&
|
||||
((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
|
||||
((_PyInterpreterFrame *)gen->gi_iframe)->f_state == FRAME_CREATED)
|
||||
gen->gi_frame_state == FRAME_CREATED)
|
||||
{
|
||||
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
|
||||
}
|
||||
|
@ -130,10 +131,9 @@ gen_dealloc(PyGenObject *gen)
|
|||
and GC_Del. */
|
||||
Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer);
|
||||
}
|
||||
if (gen->gi_frame_valid) {
|
||||
if (gen->gi_frame_state < FRAME_CLEARED) {
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
gen->gi_frame_valid = 0;
|
||||
frame->is_generator = false;
|
||||
gen->gi_frame_state = FRAME_CLEARED;
|
||||
frame->previous = NULL;
|
||||
_PyFrame_Clear(frame);
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
PyObject *result;
|
||||
|
||||
*presult = NULL;
|
||||
if (frame->f_state == FRAME_CREATED && arg && arg != Py_None) {
|
||||
if (gen->gi_frame_state == FRAME_CREATED && arg && arg != Py_None) {
|
||||
const char *msg = "can't send non-None value to a "
|
||||
"just-started generator";
|
||||
if (PyCoro_CheckExact(gen)) {
|
||||
|
@ -169,7 +169,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
PyErr_SetString(PyExc_TypeError, msg);
|
||||
return PYGEN_ERROR;
|
||||
}
|
||||
if (gen->gi_frame_valid && _PyFrame_IsExecuting(frame)) {
|
||||
if (gen->gi_frame_state == FRAME_EXECUTING) {
|
||||
const char *msg = "generator already executing";
|
||||
if (PyCoro_CheckExact(gen)) {
|
||||
msg = "coroutine already executing";
|
||||
|
@ -180,7 +180,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
PyErr_SetString(PyExc_ValueError, msg);
|
||||
return PYGEN_ERROR;
|
||||
}
|
||||
if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted(frame)) {
|
||||
if (gen->gi_frame_state >= FRAME_COMPLETED) {
|
||||
if (PyCoro_CheckExact(gen) && !closing) {
|
||||
/* `gen` is an exhausted coroutine: raise an error,
|
||||
except when called from gen_close(), which should
|
||||
|
@ -199,8 +199,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
return PYGEN_ERROR;
|
||||
}
|
||||
|
||||
assert(gen->gi_frame_valid);
|
||||
assert(_PyFrame_IsRunnable(frame));
|
||||
assert(gen->gi_frame_state < FRAME_EXECUTING);
|
||||
/* Push arg onto the frame's value stack */
|
||||
result = arg ? arg : Py_None;
|
||||
Py_INCREF(result);
|
||||
|
@ -216,7 +215,11 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
_PyErr_ChainStackItem(NULL);
|
||||
}
|
||||
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
result = _PyEval_EvalFrame(tstate, frame, exc);
|
||||
if (gen->gi_frame_state == FRAME_EXECUTING) {
|
||||
gen->gi_frame_state = FRAME_COMPLETED;
|
||||
}
|
||||
tstate->exc_info = gen->gi_exc_state.previous_item;
|
||||
gen->gi_exc_state.previous_item = NULL;
|
||||
|
||||
|
@ -229,7 +232,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
/* If the generator just returned (as opposed to yielding), signal
|
||||
* that the generator is exhausted. */
|
||||
if (result) {
|
||||
if (!_PyFrameHasCompleted(frame)) {
|
||||
if (gen->gi_frame_state == FRAME_SUSPENDED) {
|
||||
*presult = result;
|
||||
return PYGEN_NEXT;
|
||||
}
|
||||
|
@ -265,8 +268,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
/* first clean reference cycle through stored exception traceback */
|
||||
_PyErr_ClearExcState(&gen->gi_exc_state);
|
||||
|
||||
frame->is_generator = false;
|
||||
gen->gi_frame_valid = 0;
|
||||
gen->gi_frame_state = FRAME_CLEARED;
|
||||
_PyFrame_Clear(frame);
|
||||
*presult = result;
|
||||
return result ? PYGEN_RETURN : PYGEN_ERROR;
|
||||
|
@ -347,7 +349,7 @@ _PyGen_yf(PyGenObject *gen)
|
|||
{
|
||||
PyObject *yf = NULL;
|
||||
|
||||
if (gen->gi_frame_valid) {
|
||||
if (gen->gi_frame_state < FRAME_CLEARED) {
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
|
||||
if (frame->f_lasti < 1) {
|
||||
|
@ -378,11 +380,10 @@ gen_close(PyGenObject *gen, PyObject *args)
|
|||
int err = 0;
|
||||
|
||||
if (yf) {
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
PyFrameState state = frame->f_state;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_frame_state;
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
err = gen_close_iter(yf);
|
||||
frame->f_state = state;
|
||||
gen->gi_frame_state = state;
|
||||
Py_DECREF(yf);
|
||||
}
|
||||
if (err == 0)
|
||||
|
@ -429,10 +430,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
We have to allow some awaits to work it through, hence the
|
||||
`close_on_genexit` parameter here.
|
||||
*/
|
||||
PyFrameState state = frame->f_state;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_frame_state;
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
err = gen_close_iter(yf);
|
||||
frame->f_state = state;
|
||||
gen->gi_frame_state = state;
|
||||
Py_DECREF(yf);
|
||||
if (err < 0)
|
||||
return gen_send_ex(gen, Py_None, 1, 0);
|
||||
|
@ -451,11 +452,11 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
tstate->cframe->current_frame = frame;
|
||||
/* Close the generator that we are currently iterating with
|
||||
'yield from' or awaiting on with 'await'. */
|
||||
PyFrameState state = frame->f_state;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_frame_state;
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
|
||||
typ, val, tb);
|
||||
frame->f_state = state;
|
||||
gen->gi_frame_state = state;
|
||||
tstate->cframe->current_frame = prev;
|
||||
frame->previous = NULL;
|
||||
} else {
|
||||
|
@ -469,17 +470,17 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
Py_DECREF(yf);
|
||||
goto throw_here;
|
||||
}
|
||||
PyFrameState state = frame->f_state;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_frame_state;
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL);
|
||||
frame->f_state = state;
|
||||
gen->gi_frame_state = state;
|
||||
Py_DECREF(meth);
|
||||
}
|
||||
Py_DECREF(yf);
|
||||
if (!ret) {
|
||||
PyObject *val;
|
||||
/* Pop subiterator from stack */
|
||||
assert(gen->gi_frame_valid);
|
||||
assert(gen->gi_frame_state < FRAME_CLEARED);
|
||||
ret = _PyFrame_StackPop((_PyInterpreterFrame *)gen->gi_iframe);
|
||||
assert(ret == yf);
|
||||
Py_DECREF(ret);
|
||||
|
@ -756,19 +757,16 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
|
|||
static PyObject *
|
||||
gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (gen->gi_frame_valid == 0) {
|
||||
Py_RETURN_FALSE;
|
||||
if (gen->gi_frame_state == FRAME_EXECUTING) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting((_PyInterpreterFrame *)gen->gi_iframe));
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
gen_getsuspended(PyGenObject *gen, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (gen->gi_frame_valid == 0) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return PyBool_FromLong(((_PyInterpreterFrame *)gen->gi_iframe)->f_state == FRAME_SUSPENDED);
|
||||
return PyBool_FromLong(gen->gi_frame_state == FRAME_SUSPENDED);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -777,7 +775,7 @@ _gen_getframe(PyGenObject *gen, const char *const name)
|
|||
if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (gen->gi_frame_valid == 0) {
|
||||
if (gen->gi_frame_state == FRAME_CLEARED) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe));
|
||||
|
@ -899,7 +897,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
|
|||
if (gen == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
gen->gi_frame_valid = 0;
|
||||
gen->gi_frame_state = FRAME_CLEARED;
|
||||
gen->gi_code = (PyCodeObject *)func->func_code;
|
||||
Py_INCREF(gen->gi_code);
|
||||
gen->gi_weakreflist = NULL;
|
||||
|
@ -972,14 +970,13 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
|
|||
}
|
||||
/* Copy the frame */
|
||||
assert(f->f_frame->frame_obj == NULL);
|
||||
assert(f->f_owns_frame);
|
||||
assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT);
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
_PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame);
|
||||
gen->gi_frame_valid = 1;
|
||||
gen->gi_frame_state = FRAME_CREATED;
|
||||
assert(frame->frame_obj == f);
|
||||
f->f_owns_frame = 0;
|
||||
f->f_frame = frame;
|
||||
frame->is_generator = true;
|
||||
frame->owner = FRAME_OWNED_BY_GENERATOR;
|
||||
assert(PyObject_GC_IsTracked((PyObject *)f));
|
||||
gen->gi_code = PyFrame_GetCode(f);
|
||||
Py_INCREF(gen->gi_code);
|
||||
|
@ -1114,19 +1111,19 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
|||
static PyObject *
|
||||
cr_getsuspended(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (coro->cr_frame_valid == 0) {
|
||||
Py_RETURN_FALSE;
|
||||
if (coro->cr_frame_state == FRAME_SUSPENDED) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
return PyBool_FromLong(((_PyInterpreterFrame *)coro->cr_iframe)->f_state == FRAME_SUSPENDED);
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (coro->cr_frame_valid == 0) {
|
||||
Py_RETURN_FALSE;
|
||||
if (coro->cr_frame_state == FRAME_EXECUTING) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting((_PyInterpreterFrame *)coro->cr_iframe));
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -2063,7 +2060,6 @@ static PyObject *
|
|||
async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
|
||||
{
|
||||
PyGenObject *gen = (PyGenObject*)o->agt_gen;
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
PyObject *retval;
|
||||
|
||||
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
|
||||
|
@ -2073,7 +2069,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted(frame)) {
|
||||
if (gen->gi_frame_state >= FRAME_COMPLETED) {
|
||||
o->agt_state = AWAITABLE_STATE_CLOSED;
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue