summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/genobject.c
diff options
context:
space:
mode:
authorshadchin <[email protected]>2022-04-18 12:39:32 +0300
committershadchin <[email protected]>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/genobject.c
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (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.c393
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 */
};