diff options
Diffstat (limited to 'contrib/tools/python3/Objects/genobject.c')
| -rw-r--r-- | contrib/tools/python3/Objects/genobject.c | 350 |
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, }; |
