diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-25-11-09-56.gh-issue-100762.VuArrB.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-25-11-09-56.gh-issue-100762.VuArrB.rst new file mode 100644 index 00000000000000..043b65d1f74a78 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-25-11-09-56.gh-issue-100762.VuArrB.rst @@ -0,0 +1,2 @@ +Avoid expensive ``gen.throw()`` call when closing generators (and +coroutines) that can be closed trivially. diff --git a/Objects/genobject.c b/Objects/genobject.c index b9a0c30c411a00..c964d3924e84a8 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -376,6 +376,13 @@ static PyObject * gen_close(PyGenObject *gen, PyObject *args) { PyObject *retval; + if (gen->gi_frame_state == FRAME_CREATED) { + gen->gi_frame_state = FRAME_COMPLETED; + Py_RETURN_NONE; + } + if (gen->gi_frame_state >= FRAME_COMPLETED) { + Py_RETURN_NONE; + } PyObject *yf = _PyGen_yf(gen); int err = 0; @@ -386,6 +393,11 @@ gen_close(PyGenObject *gen, PyObject *args) gen->gi_frame_state = state; Py_DECREF(yf); } + _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + assert(PyBytes_CheckExact(frame->f_code->co_exceptiontable)); + if (err == 0 && PyBytes_GET_SIZE(frame->f_code->co_exceptiontable) == 0) { + Py_RETURN_NONE; + } if (err == 0) PyErr_SetNone(PyExc_GeneratorExit); retval = gen_send_ex(gen, Py_None, 1, 1);