diff options
| author | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
|---|---|---|
| committer | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
| commit | d4be68e361f4258cf0848fc70018dfe37a2acc24 (patch) | |
| tree | 153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/genobject.c | |
| parent | 260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff) | |
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects/genobject.c')
| -rw-r--r-- | contrib/tools/python3/src/Objects/genobject.c | 393 |
1 files changed, 238 insertions, 155 deletions
diff --git a/contrib/tools/python3/src/Objects/genobject.c b/contrib/tools/python3/src/Objects/genobject.c index 5ba4de82ea7..33fc4a59249 100644 --- a/contrib/tools/python3/src/Objects/genobject.c +++ b/contrib/tools/python3/src/Objects/genobject.c @@ -47,7 +47,7 @@ _PyGen_Finalize(PyObject *self) PyObject *res = NULL; PyObject *error_type, *error_value, *error_traceback; - if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) { + if (gen->gi_frame == NULL || _PyFrameHasCompleted(gen->gi_frame)) { /* Generator isn't paused, so no need to close */ return; } @@ -136,14 +136,29 @@ gen_dealloc(PyGenObject *gen) PyObject_GC_Del(gen); } -static PyObject * -gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) +static PySendResult +gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, + int exc, int closing) { PyThreadState *tstate = _PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; PyObject *result; - if (gen->gi_running) { + *presult = NULL; + if (f != NULL && f->f_lasti < 0 && arg && arg != Py_None) { + const char *msg = "can't send non-None value to a " + "just-started generator"; + if (PyCoro_CheckExact(gen)) { + msg = NON_INIT_CORO_MSG; + } + else if (PyAsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a " + "just-started async generator"; + } + PyErr_SetString(PyExc_TypeError, msg); + return PYGEN_ERROR; + } + if (f != NULL && _PyFrame_IsExecuting(f)) { const char *msg = "generator already executing"; if (PyCoro_CheckExact(gen)) { msg = "coroutine already executing"; @@ -152,9 +167,9 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) msg = "async generator already executing"; } PyErr_SetString(PyExc_ValueError, msg); - return NULL; + return PYGEN_ERROR; } - if (f == NULL || f->f_stacktop == NULL) { + if (f == NULL || _PyFrameHasCompleted(f)) { if (PyCoro_CheckExact(gen) && !closing) { /* `gen` is an exhausted coroutine: raise an error, except when called from gen_close(), which should @@ -165,37 +180,21 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) } else if (arg && !exc) { /* `gen` is an exhausted generator: - only set exception if called from send(). */ - if (PyAsyncGen_CheckExact(gen)) { - PyErr_SetNone(PyExc_StopAsyncIteration); - } - else { - PyErr_SetNone(PyExc_StopIteration); - } + only return value if called from send(). */ + *presult = Py_None; + Py_INCREF(*presult); + return PYGEN_RETURN; } - return NULL; + return PYGEN_ERROR; } - if (f->f_lasti == -1) { - if (arg && arg != Py_None) { - const char *msg = "can't send non-None value to a " - "just-started generator"; - if (PyCoro_CheckExact(gen)) { - msg = NON_INIT_CORO_MSG; - } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "can't send non-None value to a " - "just-started async generator"; - } - PyErr_SetString(PyExc_TypeError, msg); - return NULL; - } - } else { - /* Push arg onto the frame's value stack */ - result = arg ? arg : Py_None; - Py_INCREF(result); - *(f->f_stacktop++) = result; - } + assert(_PyFrame_IsRunnable(f)); + assert(f->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(f->f_code->co_code))[0] == GEN_START); + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result; + gen->gi_frame->f_stackdepth++; /* Generators always return to their most recent caller, not * necessarily their creator. */ @@ -203,7 +202,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) assert(f->f_back == NULL); f->f_back = tstate->frame; - gen->gi_running = 1; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -215,7 +213,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) result = _PyEval_EvalFrame(tstate, f, exc); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; - gen->gi_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 @@ -225,53 +222,73 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) /* If the generator just returned (as opposed to yielding), signal * that the generator is exhausted. */ - if (result && f->f_stacktop == NULL) { - if (result == Py_None) { - /* Delay exception instantiation if we can */ - if (PyAsyncGen_CheckExact(gen)) { - PyErr_SetNone(PyExc_StopAsyncIteration); - } - else { - PyErr_SetNone(PyExc_StopIteration); - } + if (result) { + if (!_PyFrameHasCompleted(f)) { + *presult = result; + return PYGEN_NEXT; } - else { - /* Async generators cannot return anything but None */ - assert(!PyAsyncGen_CheckExact(gen)); - _PyGen_SetStopIterationValue(result); + assert(result == Py_None || !PyAsyncGen_CheckExact(gen)); + if (result == Py_None && !PyAsyncGen_CheckExact(gen) && !arg) { + /* Return NULL if called by gen_iternext() */ + Py_CLEAR(result); } - Py_CLEAR(result); } - else if (!result && PyErr_ExceptionMatches(PyExc_StopIteration)) { - const char *msg = "generator raised StopIteration"; - if (PyCoro_CheckExact(gen)) { - msg = "coroutine raised StopIteration"; + else { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + const char *msg = "generator raised StopIteration"; + if (PyCoro_CheckExact(gen)) { + msg = "coroutine raised StopIteration"; + } + else if (PyAsyncGen_CheckExact(gen)) { + msg = "async generator raised StopIteration"; + } + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "async generator raised StopIteration"; + else if (PyAsyncGen_CheckExact(gen) && + PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) + { + /* code in `gen` raised a StopAsyncIteration error: + raise a RuntimeError. + */ + const char *msg = "async generator raised StopAsyncIteration"; + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); - - } - else if (!result && PyAsyncGen_CheckExact(gen) && - PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) - { - /* code in `gen` raised a StopAsyncIteration error: - raise a RuntimeError. - */ - const char *msg = "async generator raised StopAsyncIteration"; - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - if (!result || f->f_stacktop == NULL) { - /* generator can't be rerun, so release the frame */ - /* first clean reference cycle through stored exception traceback */ - _PyErr_ClearExcState(&gen->gi_exc_state); - gen->gi_frame->f_gen = NULL; - gen->gi_frame = NULL; - Py_DECREF(f); - } + /* generator can't be rerun, so release the frame */ + /* first clean reference cycle through stored exception traceback */ + _PyErr_ClearExcState(&gen->gi_exc_state); + gen->gi_frame->f_gen = NULL; + gen->gi_frame = NULL; + Py_DECREF(f); + + *presult = result; + return result ? PYGEN_RETURN : PYGEN_ERROR; +} +static PySendResult +PyGen_am_send(PyGenObject *gen, PyObject *arg, PyObject **result) +{ + return gen_send_ex2(gen, arg, result, 0, 0); +} + +static PyObject * +gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) +{ + PyObject *result; + if (gen_send_ex2(gen, arg, &result, exc, closing) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { + _PyGen_SetStopIterationValue(result); + } + Py_CLEAR(result); + } return result; } @@ -279,8 +296,8 @@ PyDoc_STRVAR(send_doc, "send(arg) -> send 'arg' into generator,\n\ return next yielded value or raise StopIteration."); -PyObject * -_PyGen_Send(PyGenObject *gen, PyObject *arg) +static PyObject * +gen_send(PyGenObject *gen, PyObject *arg) { return gen_send_ex(gen, arg, 0, 0); } @@ -326,7 +343,7 @@ _PyGen_yf(PyGenObject *gen) PyObject *yf = NULL; PyFrameObject *f = gen->gi_frame; - if (f && f->f_stacktop) { + if (f) { PyObject *bytecode = f->f_code->co_code; unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); @@ -338,9 +355,10 @@ _PyGen_yf(PyGenObject *gen) return NULL; } - if (code[f->f_lasti + sizeof(_Py_CODEUNIT)] != YIELD_FROM) + if (code[(f->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM) return NULL; - yf = f->f_stacktop[-1]; + assert(f->f_stackdepth > 0); + yf = f->f_valuestack[f->f_stackdepth-1]; Py_INCREF(yf); } @@ -355,9 +373,10 @@ gen_close(PyGenObject *gen, PyObject *args) int err = 0; if (yf) { - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; err = gen_close_iter(yf); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(yf); } if (err == 0) @@ -404,9 +423,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. */ - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; err = gen_close_iter(yf); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(yf); if (err < 0) return gen_send_ex(gen, Py_None, 1, 0); @@ -417,7 +437,6 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, PyThreadState *tstate = _PyThreadState_GET(); PyFrameObject *f = tstate->frame; - gen->gi_running = 1; /* Since we are fast-tracking things by skipping the eval loop, we need to update the current frame so the stack trace will be reported correctly to the user. */ @@ -426,10 +445,12 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, tstate->frame = gen->gi_frame; /* Close the generator that we are currently iterating with 'yield from' or awaiting on with 'await'. */ + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; ret = _gen_throw((PyGenObject *)yf, close_on_genexit, typ, val, tb); + gen->gi_frame->f_state = state; tstate->frame = f; - gen->gi_running = 0; } else { /* `yf` is an iterator or a coroutine-like object. */ PyObject *meth; @@ -441,23 +462,26 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, Py_DECREF(yf); goto throw_here; } - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(meth); } Py_DECREF(yf); if (!ret) { PyObject *val; /* Pop subiterator from stack */ - ret = *(--gen->gi_frame->f_stacktop); + assert(gen->gi_frame->f_stackdepth > 0); + gen->gi_frame->f_stackdepth--; + ret = gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth]; assert(ret == yf); Py_DECREF(ret); /* Termination repetition of YIELD_FROM */ assert(gen->gi_frame->f_lasti >= 0); - gen->gi_frame->f_lasti += sizeof(_Py_CODEUNIT); + gen->gi_frame->f_lasti += 1; if (_PyGen_FetchStopIterationValue(&val) == 0) { - ret = gen_send_ex(gen, val, 0, 0); + ret = gen_send(gen, val); Py_DECREF(val); } else { ret = gen_send_ex(gen, Py_None, 1, 0); @@ -543,7 +567,15 @@ gen_throw(PyGenObject *gen, PyObject *args) static PyObject * gen_iternext(PyGenObject *gen) { - return gen_send_ex(gen, NULL, 0, 0); + PyObject *result; + assert(PyGen_CheckExact(gen) || PyCoro_CheckExact(gen)); + if (gen_send_ex2(gen, NULL, &result, 0, 0) == PYGEN_RETURN) { + if (result != Py_None) { + _PyGen_SetStopIterationValue(result); + } + Py_CLEAR(result); + } + return result; } /* @@ -700,6 +732,16 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored)) return yf; } + +static PyObject * +gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) +{ + if (gen->gi_frame == NULL) { + Py_RETURN_FALSE; + } + return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_frame)); +} + static PyGetSetDef gen_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the generator")}, @@ -707,23 +749,31 @@ static PyGetSetDef gen_getsetlist[] = { PyDoc_STR("qualified name of the generator")}, {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, PyDoc_STR("object being iterated by yield from, or None")}, + {"gi_running", (getter)gen_getrunning, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef gen_memberlist[] = { - {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|READ_RESTRICTED}, - {"gi_running", T_BOOL, offsetof(PyGenObject, gi_running), READONLY}, - {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|READ_RESTRICTED}, + {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|PY_AUDIT_READ}, + {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ}, {NULL} /* Sentinel */ }; static PyMethodDef gen_methods[] = { - {"send",(PyCFunction)_PyGen_Send, METH_O, send_doc}, + {"send",(PyCFunction)gen_send, METH_O, send_doc}, {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, {NULL, NULL} /* Sentinel */ }; +static PyAsyncMethods gen_as_async = { + 0, /* am_await */ + 0, /* am_aiter */ + 0, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ +}; + + PyTypeObject PyGen_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "generator", /* tp_name */ @@ -734,7 +784,7 @@ PyTypeObject PyGen_Type = { 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_as_async */ + &gen_as_async, /* tp_as_async */ (reprfunc)gen_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -790,7 +840,6 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, f->f_gen = (PyObject *) gen; Py_INCREF(f->f_code); gen->gi_code = (PyObject *)(f->f_code); - gen->gi_running = 0; gen->gi_weakreflist = NULL; gen->gi_exc_state.exc_type = NULL; gen->gi_exc_state.exc_value = NULL; @@ -920,6 +969,15 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) return yf; } +static PyObject * +cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) +{ + if (coro->cr_frame == NULL) { + Py_RETURN_FALSE; + } + return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_frame)); +} + static PyGetSetDef coro_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the coroutine")}, @@ -927,13 +985,13 @@ static PyGetSetDef coro_getsetlist[] = { PyDoc_STR("qualified name of the coroutine")}, {"cr_await", (getter)coro_get_cr_await, NULL, PyDoc_STR("object being awaited on, or None")}, + {"cr_running", (getter)cr_getrunning, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef coro_memberlist[] = { - {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|READ_RESTRICTED}, - {"cr_running", T_BOOL, offsetof(PyCoroObject, cr_running), READONLY}, - {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|READ_RESTRICTED}, + {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|PY_AUDIT_READ}, + {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ}, {"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin), READONLY}, {NULL} /* Sentinel */ }; @@ -950,7 +1008,7 @@ PyDoc_STRVAR(coro_close_doc, "close() -> raise GeneratorExit inside coroutine."); static PyMethodDef coro_methods[] = { - {"send",(PyCFunction)_PyGen_Send, METH_O, coro_send_doc}, + {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, {"throw",(PyCFunction)gen_throw, METH_VARARGS, coro_throw_doc}, {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, {NULL, NULL} /* Sentinel */ @@ -959,7 +1017,8 @@ static PyMethodDef coro_methods[] = { static PyAsyncMethods coro_as_async = { (unaryfunc)coro_await, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ }; PyTypeObject PyCoro_Type = { @@ -1025,13 +1084,13 @@ coro_wrapper_dealloc(PyCoroWrapper *cw) static PyObject * coro_wrapper_iternext(PyCoroWrapper *cw) { - return gen_send_ex((PyGenObject *)cw->cw_coroutine, NULL, 0, 0); + return gen_iternext((PyGenObject *)cw->cw_coroutine); } static PyObject * coro_wrapper_send(PyCoroWrapper *cw, PyObject *arg) { - return gen_send_ex((PyGenObject *)cw->cw_coroutine, arg, 0, 0); + return gen_send((PyGenObject *)cw->cw_coroutine, arg); } static PyObject * @@ -1171,7 +1230,7 @@ typedef enum { } AwaitableState; -typedef struct { +typedef struct PyAsyncGenASend { PyObject_HEAD PyAsyncGenObject *ags_gen; @@ -1183,7 +1242,7 @@ typedef struct { } PyAsyncGenASend; -typedef struct { +typedef struct PyAsyncGenAThrow { PyObject_HEAD PyAsyncGenObject *agt_gen; @@ -1195,28 +1254,12 @@ typedef struct { } PyAsyncGenAThrow; -typedef struct { +typedef struct _PyAsyncGenWrappedValue { PyObject_HEAD PyObject *agw_val; } _PyAsyncGenWrappedValue; -#ifndef _PyAsyncGen_MAXFREELIST -#define _PyAsyncGen_MAXFREELIST 80 -#endif - -/* Freelists boost performance 6-10%; they also reduce memory - fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend - are short-living objects that are instantiated for every - __anext__ call. -*/ - -static _PyAsyncGenWrappedValue *ag_value_freelist[_PyAsyncGen_MAXFREELIST]; -static int ag_value_freelist_free = 0; - -static PyAsyncGenASend *ag_asend_freelist[_PyAsyncGen_MAXFREELIST]; -static int ag_asend_freelist_free = 0; - #define _PyAsyncGenWrappedValue_CheckExact(o) \ Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type) @@ -1328,12 +1371,10 @@ static PyGetSetDef async_gen_getsetlist[] = { }; static PyMemberDef async_gen_memberlist[] = { - {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), - READONLY|READ_RESTRICTED}, + {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY|PY_AUDIT_READ}, {"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async), READONLY}, - {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), - READONLY|READ_RESTRICTED}, + {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ}, {NULL} /* Sentinel */ }; @@ -1359,7 +1400,8 @@ static PyMethodDef async_gen_methods[] = { static PyAsyncMethods async_gen_as_async = { 0, /* am_await */ PyObject_SelfIter, /* am_aiter */ - (unaryfunc)async_gen_anext /* am_anext */ + (unaryfunc)async_gen_anext, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ }; @@ -1416,6 +1458,14 @@ PyTypeObject PyAsyncGen_Type = { }; +static struct _Py_async_gen_state * +get_async_gen_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->async_gen; +} + + PyObject * PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) { @@ -1434,27 +1484,34 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) void -_PyAsyncGen_ClearFreeLists(void) +_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp) { - while (ag_value_freelist_free) { + struct _Py_async_gen_state *state = &interp->async_gen; + + while (state->value_numfree) { _PyAsyncGenWrappedValue *o; - o = ag_value_freelist[--ag_value_freelist_free]; + o = state->value_freelist[--state->value_numfree]; assert(_PyAsyncGenWrappedValue_CheckExact(o)); PyObject_GC_Del(o); } - while (ag_asend_freelist_free) { + while (state->asend_numfree) { PyAsyncGenASend *o; - o = ag_asend_freelist[--ag_asend_freelist_free]; + o = state->asend_freelist[--state->asend_numfree]; assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type)); PyObject_GC_Del(o); } } void -_PyAsyncGen_Fini(void) +_PyAsyncGen_Fini(PyInterpreterState *interp) { - _PyAsyncGen_ClearFreeLists(); + _PyAsyncGen_ClearFreeLists(interp); +#ifdef Py_DEBUG + struct _Py_async_gen_state *state = &interp->async_gen; + state->value_numfree = -1; + state->asend_numfree = -1; +#endif } @@ -1497,10 +1554,16 @@ async_gen_asend_dealloc(PyAsyncGenASend *o) _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->ags_gen); Py_CLEAR(o->ags_sendval); - if (ag_asend_freelist_free < _PyAsyncGen_MAXFREELIST) { + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini() + assert(state->asend_numfree != -1); +#endif + if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) { assert(PyAsyncGenASend_CheckExact(o)); - ag_asend_freelist[ag_asend_freelist_free++] = o; - } else { + state->asend_freelist[state->asend_numfree++] = o; + } + else { PyObject_GC_Del(o); } } @@ -1541,7 +1604,7 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) } o->ags_gen->ag_running_async = 1; - result = gen_send_ex((PyGenObject*)o->ags_gen, arg, 0, 0); + result = gen_send((PyGenObject*)o->ags_gen, arg); result = async_gen_unwrap_value(o->ags_gen, result); if (result == NULL) { @@ -1601,7 +1664,8 @@ static PyMethodDef async_gen_asend_methods[] = { static PyAsyncMethods async_gen_asend_as_async = { PyObject_SelfIter, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + 0, /* am_send */ }; @@ -1652,11 +1716,17 @@ static PyObject * async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) { PyAsyncGenASend *o; - if (ag_asend_freelist_free) { - ag_asend_freelist_free--; - o = ag_asend_freelist[ag_asend_freelist_free]; + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_asend_new() must not be called after _PyAsyncGen_Fini() + assert(state->asend_numfree != -1); +#endif + if (state->asend_numfree) { + state->asend_numfree--; + o = state->asend_freelist[state->asend_numfree]; _Py_NewReference((PyObject *)o); - } else { + } + else { o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); if (o == NULL) { return NULL; @@ -1684,10 +1754,16 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o) { _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->agw_val); - if (ag_value_freelist_free < _PyAsyncGen_MAXFREELIST) { + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini() + assert(state->value_numfree != -1); +#endif + if (state->value_numfree < _PyAsyncGen_MAXFREELIST) { assert(_PyAsyncGenWrappedValue_CheckExact(o)); - ag_value_freelist[ag_value_freelist_free++] = o; - } else { + state->value_freelist[state->value_numfree++] = o; + } + else { PyObject_GC_Del(o); } } @@ -1751,12 +1827,18 @@ _PyAsyncGenValueWrapperNew(PyObject *val) _PyAsyncGenWrappedValue *o; assert(val); - if (ag_value_freelist_free) { - ag_value_freelist_free--; - o = ag_value_freelist[ag_value_freelist_free]; + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini() + assert(state->value_numfree != -1); +#endif + if (state->value_numfree) { + state->value_numfree--; + o = state->value_freelist[state->value_numfree]; assert(_PyAsyncGenWrappedValue_CheckExact(o)); _Py_NewReference((PyObject*)o); - } else { + } + else { o = PyObject_GC_New(_PyAsyncGenWrappedValue, &_PyAsyncGenWrappedValue_Type); if (o == NULL) { @@ -1806,7 +1888,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) return NULL; } - if (f == NULL || f->f_stacktop == NULL) { + if (f == NULL || _PyFrameHasCompleted(f)) { o->agt_state = AWAITABLE_STATE_CLOSED; PyErr_SetNone(PyExc_StopIteration); return NULL; @@ -1879,7 +1961,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) assert(o->agt_state == AWAITABLE_STATE_ITER); - retval = gen_send_ex((PyGenObject *)gen, arg, 0, 0); + retval = gen_send((PyGenObject *)gen, arg); if (o->agt_args) { return async_gen_unwrap_value(o->agt_gen, retval); } else { @@ -1991,7 +2073,8 @@ static PyMethodDef async_gen_athrow_methods[] = { static PyAsyncMethods async_gen_athrow_as_async = { PyObject_SelfIter, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + 0, /* am_send */ }; |
