summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Objects/genobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Objects/genobject.c')
-rw-r--r--contrib/tools/python3/Objects/genobject.c350
1 files changed, 197 insertions, 153 deletions
diff --git a/contrib/tools/python3/Objects/genobject.c b/contrib/tools/python3/Objects/genobject.c
index 640a7d906c8..b19ff252ddb 100644
--- a/contrib/tools/python3/Objects/genobject.c
+++ b/contrib/tools/python3/Objects/genobject.c
@@ -6,13 +6,16 @@
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_EvalFrame()
#include "pycore_frame.h" // _PyInterpreterFrame
-#include "pycore_genobject.h" // struct _Py_async_gen_state
+#include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED()
+#include "pycore_genobject.h" // struct _Py_async_gen_freelist
+#include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
+#include "pycore_opcode_utils.h" // RESUME_AFTER_YIELD_FROM
+#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_*
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
#include "pycore_pystate.h" // _PyThreadState_GET()
-#include "structmember.h" // PyMemberDef
-#include "opcode.h" // SEND
-#include "frameobject.h" // _PyInterpreterFrame_GetLine
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
+
#include "pystats.h"
static PyObject *gen_close(PyGenObject *, PyObject *);
@@ -29,7 +32,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
static inline PyCodeObject *
_PyGen_GetCode(PyGenObject *gen) {
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe);
- return frame->f_code;
+ return _PyFrame_GetCode(frame);
}
PyCodeObject *
@@ -40,19 +43,12 @@ PyGen_GetCode(PyGenObject *gen) {
return res;
}
-static inline int
-exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
-{
- Py_VISIT(exc_state->exc_value);
- return 0;
-}
-
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
Py_VISIT(gen->gi_name);
Py_VISIT(gen->gi_qualname);
- if (gen->gi_frame_state < FRAME_CLEARED) {
+ if (gen->gi_frame_state != FRAME_CLEARED) {
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe);
assert(frame->frame_obj == NULL ||
frame->frame_obj->f_frame->owner == FRAME_OWNED_BY_GENERATOR);
@@ -63,7 +59,8 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
}
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
participate in a reference cycle. */
- return exc_state_traverse(&gen->gi_exc_state, visit, arg);
+ Py_VISIT(gen->gi_exc_state.exc_value);
+ return 0;
}
void
@@ -71,7 +68,7 @@ _PyGen_Finalize(PyObject *self)
{
PyGenObject *gen = (PyGenObject *)self;
- if (gen->gi_frame_state >= FRAME_COMPLETED) {
+ if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
/* Generator isn't paused, so no need to close */
return;
}
@@ -123,14 +120,26 @@ _PyGen_Finalize(PyObject *self)
}
static void
+gen_clear_frame(PyGenObject *gen)
+{
+ if (gen->gi_frame_state == FRAME_CLEARED)
+ return;
+
+ gen->gi_frame_state = FRAME_CLEARED;
+ _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
+ frame->previous = NULL;
+ _PyFrame_ClearExceptCode(frame);
+ _PyErr_ClearExcState(&gen->gi_exc_state);
+}
+
+static void
gen_dealloc(PyGenObject *gen)
{
PyObject *self = (PyObject *) gen;
_PyObject_GC_UNTRACK(gen);
- if (gen->gi_weakreflist != NULL)
- PyObject_ClearWeakRefs(self);
+ FT_CLEAR_WEAKREFS(self, gen->gi_weakreflist);
_PyObject_GC_TRACK(self);
@@ -144,19 +153,15 @@ gen_dealloc(PyGenObject *gen)
and GC_Del. */
Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer);
}
- if (gen->gi_frame_state < FRAME_CLEARED) {
- _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
- gen->gi_frame_state = FRAME_CLEARED;
- frame->previous = NULL;
- _PyFrame_ClearExceptCode(frame);
- }
+ gen_clear_frame(gen);
+ assert(gen->gi_exc_state.exc_value == NULL);
if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE) {
Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer);
}
Py_DECREF(_PyGen_GetCode(gen));
Py_CLEAR(gen->gi_name);
Py_CLEAR(gen->gi_qualname);
- _PyErr_ClearExcState(&gen->gi_exc_state);
+
PyObject_GC_Del(gen);
}
@@ -166,7 +171,6 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
{
PyThreadState *tstate = _PyThreadState_GET();
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
- PyObject *result;
*presult = NULL;
if (gen->gi_frame_state == FRAME_CREATED && arg && arg != Py_None) {
@@ -193,7 +197,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
PyErr_SetString(PyExc_ValueError, msg);
return PYGEN_ERROR;
}
- if (gen->gi_frame_state >= FRAME_COMPLETED) {
+ if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
if (PyCoro_CheckExact(gen) && !closing) {
/* `gen` is an exhausted coroutine: raise an error,
except when called from gen_close(), which should
@@ -211,10 +215,12 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
return PYGEN_ERROR;
}
- assert(gen->gi_frame_state < FRAME_EXECUTING);
+ assert((gen->gi_frame_state == FRAME_CREATED) ||
+ FRAME_STATE_SUSPENDED(gen->gi_frame_state));
+
/* Push arg onto the frame's value stack */
- result = arg ? arg : Py_None;
- _PyFrame_StackPush(frame, Py_NewRef(result));
+ PyObject *arg_obj = arg ? arg : Py_None;
+ _PyFrame_StackPush(frame, Py_NewRef(arg_obj));
_PyErr_StackItem *prev_exc_info = tstate->exc_info;
gen->gi_exc_state.previous_item = prev_exc_info;
@@ -222,12 +228,12 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
if (exc) {
assert(_PyErr_Occurred(tstate));
- _PyErr_ChainStackItem(NULL);
+ _PyErr_ChainStackItem();
}
gen->gi_frame_state = FRAME_EXECUTING;
EVAL_CALL_STAT_INC(EVAL_CALL_GENERATOR);
- result = _PyEval_EvalFrame(tstate, frame, exc);
+ PyObject *result = _PyEval_EvalFrame(tstate, frame, exc);
assert(tstate->exc_info == prev_exc_info);
assert(gen->gi_exc_state.previous_item == NULL);
assert(gen->gi_frame_state != FRAME_EXECUTING);
@@ -236,7 +242,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 (gen->gi_frame_state == FRAME_SUSPENDED) {
+ if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) {
*presult = result;
return PYGEN_NEXT;
}
@@ -252,10 +258,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
!PyErr_ExceptionMatches(PyExc_StopAsyncIteration));
}
- /* generator can't be rerun, so release the frame */
- /* first clean reference cycle through stored exception traceback */
- _PyErr_ClearExcState(&gen->gi_exc_state);
-
+ assert(gen->gi_exc_state.exc_value == NULL);
assert(gen->gi_frame_state == FRAME_CLEARED);
*presult = result;
return result ? PYGEN_RETURN : PYGEN_ERROR;
@@ -288,7 +291,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
}
PyDoc_STRVAR(send_doc,
-"send(arg) -> send 'arg' into generator,\n\
+"send(value) -> send 'value' into generator,\n\
return next yielded value or raise StopIteration.");
static PyObject *
@@ -317,7 +320,7 @@ gen_close_iter(PyObject *yf)
}
else {
PyObject *meth;
- if (_PyObject_LookupAttr(yf, &_Py_ID(close), &meth) < 0) {
+ if (PyObject_GetOptionalAttr(yf, &_Py_ID(close), &meth) < 0) {
PyErr_WriteUnraisable(yf);
}
if (meth) {
@@ -334,56 +337,42 @@ gen_close_iter(PyObject *yf)
static inline bool
is_resume(_Py_CODEUNIT *instr)
{
- return instr->op.code == RESUME || instr->op.code == INSTRUMENTED_RESUME;
-}
-
-static inline bool
-is_yield(_Py_CODEUNIT *instr)
-{
- return instr->op.code == YIELD_VALUE || instr->op.code == INSTRUMENTED_YIELD_VALUE;
+ uint8_t code = FT_ATOMIC_LOAD_UINT8_RELAXED(instr->op.code);
+ return (
+ code == RESUME ||
+ code == RESUME_CHECK ||
+ code == INSTRUMENTED_RESUME
+ );
}
PyObject *
_PyGen_yf(PyGenObject *gen)
{
- PyObject *yf = NULL;
-
- if (gen->gi_frame_state < FRAME_CLEARED) {
+ if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) {
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
-
- if (gen->gi_frame_state == FRAME_CREATED) {
- /* Return immediately if the frame didn't start yet. SEND
- always come after LOAD_CONST: a code object should not start
- with SEND */
- assert(_PyCode_CODE(_PyGen_GetCode(gen))[0].op.code != SEND);
- return NULL;
- }
- _Py_CODEUNIT next = frame->prev_instr[1];
- if (!is_resume(&next) || next.op.arg < 2)
- {
- /* Not in a yield from */
- return NULL;
- }
- yf = Py_NewRef(_PyFrame_StackPeek(frame));
+ assert(is_resume(frame->instr_ptr));
+ assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM);
+ return Py_NewRef(_PyFrame_StackPeek(frame));
}
-
- return yf;
+ return NULL;
}
static PyObject *
gen_close(PyGenObject *gen, PyObject *args)
{
PyObject *retval;
- PyObject *yf = _PyGen_yf(gen);
int err = 0;
+
if (gen->gi_frame_state == FRAME_CREATED) {
gen->gi_frame_state = FRAME_COMPLETED;
+ gen_clear_frame(gen);
Py_RETURN_NONE;
}
- if (gen->gi_frame_state >= FRAME_COMPLETED) {
+ if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
Py_RETURN_NONE;
}
+ PyObject *yf = _PyGen_yf(gen);
if (yf) {
PyFrameState state = gen->gi_frame_state;
gen->gi_frame_state = FRAME_EXECUTING;
@@ -392,16 +381,17 @@ gen_close(PyGenObject *gen, PyObject *args)
Py_DECREF(yf);
}
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
- /* It is possible for the previous instruction to not be a
- * YIELD_VALUE if the debugger has changed the lineno. */
- if (err == 0 && is_yield(frame->prev_instr)) {
- assert(is_resume(frame->prev_instr + 1));
- int exception_handler_depth = frame->prev_instr[0].op.code;
- assert(exception_handler_depth > 0);
+ if (is_resume(frame->instr_ptr)) {
+ bool no_unwind_tools = _PyEval_NoToolsForUnwind(_PyThreadState_GET());
/* We can safely ignore the outermost try block
- * as it automatically generated to handle
+ * as it is automatically generated to handle
* StopIteration. */
- if (exception_handler_depth == 1) {
+ int oparg = frame->instr_ptr->op.arg;
+ if (oparg & RESUME_OPARG_DEPTH1_MASK && no_unwind_tools) {
+ // RESUME after YIELD_VALUE and exception depth is 1
+ assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START);
+ gen->gi_frame_state = FRAME_COMPLETED;
+ gen_clear_frame(gen);
Py_RETURN_NONE;
}
}
@@ -420,11 +410,16 @@ gen_close(PyGenObject *gen, PyObject *args)
PyErr_SetString(PyExc_RuntimeError, msg);
return NULL;
}
- if (PyErr_ExceptionMatches(PyExc_StopIteration)
- || PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
- PyErr_Clear(); /* ignore these errors */
+ assert(PyErr_Occurred());
+ if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
+ PyErr_Clear(); /* ignore this error */
Py_RETURN_NONE;
}
+ /* if the generator returned a value while closing, StopIteration was
+ * raised in gen_send_ex() above; retrieve and return the value here */
+ if (_PyGen_FetchStopIterationValue(&retval) == 0) {
+ return retval;
+ }
return NULL;
}
@@ -472,9 +467,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
will be reported correctly to the user. */
/* XXX We should probably be updating the current frame
somewhere in ceval.c. */
- _PyInterpreterFrame *prev = tstate->cframe->current_frame;
+ _PyInterpreterFrame *prev = tstate->current_frame;
frame->previous = prev;
- tstate->cframe->current_frame = frame;
+ tstate->current_frame = frame;
/* Close the generator that we are currently iterating with
'yield from' or awaiting on with 'await'. */
PyFrameState state = gen->gi_frame_state;
@@ -482,12 +477,12 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
typ, val, tb);
gen->gi_frame_state = state;
- tstate->cframe->current_frame = prev;
+ tstate->current_frame = prev;
frame->previous = NULL;
} else {
/* `yf` is an iterator or a coroutine-like object. */
PyObject *meth;
- if (_PyObject_LookupAttr(yf, &_Py_ID(throw), &meth) < 0) {
+ if (PyObject_GetOptionalAttr(yf, &_Py_ID(throw), &meth) < 0) {
Py_DECREF(yf);
return NULL;
}
@@ -730,7 +725,7 @@ gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored))
static PyObject *
gen_getsuspended(PyGenObject *gen, void *Py_UNUSED(ignored))
{
- return PyBool_FromLong(gen->gi_frame_state == FRAME_SUSPENDED);
+ return PyBool_FromLong(FRAME_STATE_SUSPENDED(gen->gi_frame_state));
}
static PyObject *
@@ -802,6 +797,7 @@ static PyMethodDef gen_methods[] = {
{"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc},
{"close",(PyCFunction)gen_close, METH_NOARGS, close_doc},
{"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__},
+ {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL} /* Sentinel */
};
@@ -923,7 +919,7 @@ _Py_MakeCoro(PyFunctionObject *func)
if (origin_depth == 0) {
((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL;
} else {
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
assert(frame);
assert(_PyFrame_IsIncomplete(frame));
frame = _PyFrame_GetFirstComplete(frame->previous);
@@ -941,7 +937,7 @@ static PyObject *
gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
PyObject *name, PyObject *qualname)
{
- PyCodeObject *code = f->f_frame->f_code;
+ PyCodeObject *code = _PyFrame_GetCode(f->f_frame);
int size = code->co_nlocalsplus + code->co_stacksize;
PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size);
if (gen == NULL) {
@@ -1085,7 +1081,7 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
static PyObject *
cr_getsuspended(PyCoroObject *coro, void *Py_UNUSED(ignored))
{
- if (coro->cr_frame_state == FRAME_SUSPENDED) {
+ if (FRAME_STATE_SUSPENDED(coro->cr_frame_state)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
@@ -1128,7 +1124,7 @@ static PyGetSetDef coro_getsetlist[] = {
};
static PyMemberDef coro_memberlist[] = {
- {"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin_or_finalizer), READONLY},
+ {"cr_origin", _Py_T_OBJECT, offsetof(PyCoroObject, cr_origin_or_finalizer), Py_READONLY},
{NULL} /* Sentinel */
};
@@ -1154,6 +1150,7 @@ static PyMethodDef coro_methods[] = {
{"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc},
{"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc},
{"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__},
+ {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL} /* Sentinel */
};
@@ -1323,7 +1320,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame)
}
frame = current_frame;
for (int i = 0; i < frame_count; ++i) {
- PyCodeObject *code = frame->f_code;
+ PyCodeObject *code = _PyFrame_GetCode(frame);
int line = PyUnstable_InterpreterFrame_GetLine(frame);
PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line,
code->co_name);
@@ -1522,7 +1519,7 @@ ag_getcode(PyGenObject *gen, void *Py_UNUSED(ignored))
static PyObject *
ag_getsuspended(PyAsyncGenObject *ag, void *Py_UNUSED(ignored))
{
- if (ag->ag_frame_state == FRAME_SUSPENDED) {
+ if (FRAME_STATE_SUSPENDED(ag->ag_frame_state)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
@@ -1542,8 +1539,8 @@ static PyGetSetDef async_gen_getsetlist[] = {
};
static PyMemberDef async_gen_memberlist[] = {
- {"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
- READONLY},
+ {"ag_running", Py_T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
+ Py_READONLY},
{NULL} /* Sentinel */
};
@@ -1634,12 +1631,19 @@ PyTypeObject PyAsyncGen_Type = {
};
-#if _PyAsyncGen_MAXFREELIST > 0
-static struct _Py_async_gen_state *
-get_async_gen_state(void)
+#ifdef WITH_FREELISTS
+static struct _Py_async_gen_freelist *
+get_async_gen_freelist(void)
{
- PyInterpreterState *interp = _PyInterpreterState_GET();
- return &interp->async_gen;
+ struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+ return &freelists->async_gens;
+}
+
+static struct _Py_async_gen_asend_freelist *
+get_async_gen_asend_freelist(void)
+{
+ struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+ return &freelists->async_gen_asends;
}
#endif
@@ -1662,39 +1666,34 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
void
-_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
+_PyAsyncGen_ClearFreeLists(struct _Py_object_freelists *freelist_state, int is_finalization)
{
-#if _PyAsyncGen_MAXFREELIST > 0
- struct _Py_async_gen_state *state = &interp->async_gen;
+#ifdef WITH_FREELISTS
+ struct _Py_async_gen_freelist *freelist = &freelist_state->async_gens;
- while (state->value_numfree) {
+ while (freelist->numfree > 0) {
_PyAsyncGenWrappedValue *o;
- o = state->value_freelist[--state->value_numfree];
+ o = freelist->items[--freelist->numfree];
assert(_PyAsyncGenWrappedValue_CheckExact(o));
PyObject_GC_Del(o);
}
- while (state->asend_numfree) {
+ struct _Py_async_gen_asend_freelist *asend_freelist = &freelist_state->async_gen_asends;
+
+ while (asend_freelist->numfree > 0) {
PyAsyncGenASend *o;
- o = state->asend_freelist[--state->asend_numfree];
+ o = asend_freelist->items[--asend_freelist->numfree];
assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
PyObject_GC_Del(o);
}
-#endif
-}
-void
-_PyAsyncGen_Fini(PyInterpreterState *interp)
-{
- _PyAsyncGen_ClearFreeLists(interp);
-#if defined(Py_DEBUG) && _PyAsyncGen_MAXFREELIST > 0
- struct _Py_async_gen_state *state = &interp->async_gen;
- state->value_numfree = -1;
- state->asend_numfree = -1;
+ if (is_finalization) {
+ freelist->numfree = -1;
+ asend_freelist->numfree = -1;
+ }
#endif
}
-
static PyObject *
async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
{
@@ -1731,18 +1730,19 @@ async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
static void
async_gen_asend_dealloc(PyAsyncGenASend *o)
{
+ if (PyObject_CallFinalizerFromDealloc((PyObject *)o)) {
+ return;
+ }
+
_PyObject_GC_UNTRACK((PyObject *)o);
Py_CLEAR(o->ags_gen);
Py_CLEAR(o->ags_sendval);
-#if _PyAsyncGen_MAXFREELIST > 0
- 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) {
+#ifdef WITH_FREELISTS
+ struct _Py_async_gen_asend_freelist *freelist = get_async_gen_asend_freelist();
+ if (freelist->numfree >= 0 && freelist->numfree < _PyAsyncGen_MAXFREELIST) {
assert(PyAsyncGenASend_CheckExact(o));
- state->asend_freelist[state->asend_numfree++] = o;
+ _PyGC_CLEAR_FINALIZED((PyObject *)o);
+ freelist->items[freelist->numfree++] = o;
}
else
#endif
@@ -1846,10 +1846,34 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t narg
static PyObject *
async_gen_asend_close(PyAsyncGenASend *o, PyObject *args)
{
- o->ags_state = AWAITABLE_STATE_CLOSED;
- Py_RETURN_NONE;
+ PyObject *result;
+ if (o->ags_state == AWAITABLE_STATE_CLOSED) {
+ Py_RETURN_NONE;
+ }
+ result = async_gen_asend_throw(o, &PyExc_GeneratorExit, 1);
+ if (result == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
+ PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
+ PyErr_ExceptionMatches(PyExc_GeneratorExit))
+ {
+ PyErr_Clear();
+ Py_RETURN_NONE;
+ }
+ return result;
+ } else {
+ Py_DECREF(result);
+ PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
+ return NULL;
+ }
}
+static void
+async_gen_asend_finalize(PyAsyncGenASend *o)
+{
+ if (o->ags_state == AWAITABLE_STATE_INIT) {
+ _PyErr_WarnUnawaitedAgenMethod(o->ags_gen, &_Py_ID(asend));
+ }
+}
static PyMethodDef async_gen_asend_methods[] = {
{"send", (PyCFunction)async_gen_asend_send, METH_O, send_doc},
@@ -1907,6 +1931,7 @@ PyTypeObject _PyAsyncGenASend_Type = {
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
+ .tp_finalize = (destructor)async_gen_asend_finalize,
};
@@ -1914,15 +1939,11 @@ static PyObject *
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
{
PyAsyncGenASend *o;
-#if _PyAsyncGen_MAXFREELIST > 0
- 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];
+#ifdef WITH_FREELISTS
+ struct _Py_async_gen_asend_freelist *freelist = get_async_gen_asend_freelist();
+ if (freelist->numfree > 0) {
+ freelist->numfree--;
+ o = freelist->items[freelist->numfree];
_Py_NewReference((PyObject *)o);
}
else
@@ -1953,15 +1974,11 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
{
_PyObject_GC_UNTRACK((PyObject *)o);
Py_CLEAR(o->agw_val);
-#if _PyAsyncGen_MAXFREELIST > 0
- 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) {
+#ifdef WITH_FREELISTS
+ struct _Py_async_gen_freelist *freelist = get_async_gen_freelist();
+ if (freelist->numfree >= 0 && freelist->numfree < _PyAsyncGen_MAXFREELIST) {
assert(_PyAsyncGenWrappedValue_CheckExact(o));
- state->value_freelist[state->value_numfree++] = o;
+ freelist->items[freelist->numfree++] = o;
OBJECT_STAT_INC(to_freelist);
}
else
@@ -2030,15 +2047,11 @@ _PyAsyncGenValueWrapperNew(PyThreadState *tstate, PyObject *val)
_PyAsyncGenWrappedValue *o;
assert(val);
-#if _PyAsyncGen_MAXFREELIST > 0
- struct _Py_async_gen_state *state = &tstate->interp->async_gen;
-#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];
+#ifdef WITH_FREELISTS
+ struct _Py_async_gen_freelist *freelist = get_async_gen_freelist();
+ if (freelist->numfree > 0) {
+ freelist->numfree--;
+ o = freelist->items[freelist->numfree];
OBJECT_STAT_INC(from_freelist);
assert(_PyAsyncGenWrappedValue_CheckExact(o));
_Py_NewReference((PyObject*)o);
@@ -2064,6 +2077,10 @@ _PyAsyncGenValueWrapperNew(PyThreadState *tstate, PyObject *val)
static void
async_gen_athrow_dealloc(PyAsyncGenAThrow *o)
{
+ if (PyObject_CallFinalizerFromDealloc((PyObject *)o)) {
+ return;
+ }
+
_PyObject_GC_UNTRACK((PyObject *)o);
Py_CLEAR(o->agt_gen);
Py_CLEAR(o->agt_args);
@@ -2093,7 +2110,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
return NULL;
}
- if (gen->gi_frame_state >= FRAME_COMPLETED) {
+ if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
o->agt_state = AWAITABLE_STATE_CLOSED;
PyErr_SetNone(PyExc_StopIteration);
return NULL;
@@ -2291,11 +2308,37 @@ async_gen_athrow_iternext(PyAsyncGenAThrow *o)
static PyObject *
async_gen_athrow_close(PyAsyncGenAThrow *o, PyObject *args)
{
- o->agt_state = AWAITABLE_STATE_CLOSED;
- Py_RETURN_NONE;
+ PyObject *result;
+ if (o->agt_state == AWAITABLE_STATE_CLOSED) {
+ Py_RETURN_NONE;
+ }
+ result = async_gen_athrow_throw(o, &PyExc_GeneratorExit, 1);
+ if (result == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
+ PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
+ PyErr_ExceptionMatches(PyExc_GeneratorExit))
+ {
+ PyErr_Clear();
+ Py_RETURN_NONE;
+ }
+ return result;
+ } else {
+ Py_DECREF(result);
+ PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
+ return NULL;
+ }
}
+static void
+async_gen_athrow_finalize(PyAsyncGenAThrow *o)
+{
+ if (o->agt_state == AWAITABLE_STATE_INIT) {
+ PyObject *method = o->agt_args ? &_Py_ID(athrow) : &_Py_ID(aclose);
+ _PyErr_WarnUnawaitedAgenMethod(o->agt_gen, method);
+ }
+}
+
static PyMethodDef async_gen_athrow_methods[] = {
{"send", (PyCFunction)async_gen_athrow_send, METH_O, send_doc},
{"throw", _PyCFunction_CAST(async_gen_athrow_throw),
@@ -2353,6 +2396,7 @@ PyTypeObject _PyAsyncGenAThrow_Type = {
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
+ .tp_finalize = (destructor)async_gen_athrow_finalize,
};