diff options
author | Vladimir Matveev <vladima@fb.com> | 2020-09-18 18:38:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-18 18:38:38 -0700 |
commit | 2b05361bf7cbbd76035206fd9befe87f37489f1e (patch) | |
tree | d29b4c3ab8e617ee8f5f5440db83a2bfa3050666 /Python/ceval.c | |
parent | Make fractional value accumulation consistent inside and outside the loop. (G... (diff) | |
download | cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.tar.gz cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.tar.bz2 cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.zip |
bpo-41756: Introduce PyGen_Send C API (GH-22196)
The new API allows to efficiently send values into native generators
and coroutines avoiding use of StopIteration exceptions to signal
returns.
ceval loop now uses this method instead of the old "private"
_PyGen_Send C API. This translates to 1.6x increased performance
of 'await' calls in micro-benchmarks.
Aside from CPython core improvements, this new API will also allow
Cython to generate more efficient code, benefiting high-performance
IO libraries like uvloop.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index f747faaebf0..3de372f45a2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2223,29 +2223,53 @@ main_loop: case TARGET(YIELD_FROM): { PyObject *v = POP(); PyObject *receiver = TOP(); - int err; - if (PyGen_CheckExact(receiver) || PyCoro_CheckExact(receiver)) { - retval = _PyGen_Send((PyGenObject *)receiver, v); + int is_gen_or_coro = PyGen_CheckExact(receiver) || PyCoro_CheckExact(receiver); + int gen_status; + if (tstate->c_tracefunc == NULL && is_gen_or_coro) { + gen_status = PyGen_Send((PyGenObject *)receiver, v, &retval); } else { - _Py_IDENTIFIER(send); - if (v == Py_None) - retval = Py_TYPE(receiver)->tp_iternext(receiver); - else - retval = _PyObject_CallMethodIdOneArg(receiver, &PyId_send, v); + if (is_gen_or_coro) { + retval = _PyGen_Send((PyGenObject *)receiver, v); + } + else { + _Py_IDENTIFIER(send); + if (v == Py_None) { + retval = Py_TYPE(receiver)->tp_iternext(receiver); + } + else { + retval = _PyObject_CallMethodIdOneArg(receiver, &PyId_send, v); + } + } + + if (retval == NULL) { + if (tstate->c_tracefunc != NULL + && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f); + if (_PyGen_FetchStopIterationValue(&retval) == 0) { + gen_status = PYGEN_RETURN; + } + else { + gen_status = PYGEN_ERROR; + } + } + else { + gen_status = PYGEN_NEXT; + } } Py_DECREF(v); - if (retval == NULL) { - PyObject *val; - if (tstate->c_tracefunc != NULL - && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f); - err = _PyGen_FetchStopIterationValue(&val); - if (err < 0) - goto error; + if (gen_status == PYGEN_ERROR) { + assert (retval == NULL); + goto error; + } + if (gen_status == PYGEN_RETURN) { + assert (retval != NULL); + Py_DECREF(receiver); - SET_TOP(val); + SET_TOP(retval); + retval = NULL; DISPATCH(); } + assert (gen_status == PYGEN_NEXT); /* receiver remains on stack, retval is value to be yielded */ /* and repeat... */ assert(f->f_lasti >= (int)sizeof(_Py_CODEUNIT)); |