From 6ee3f3814f17c72b96c424873de64a4602d9788a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 17 Mar 2022 11:33:32 -0700 Subject: [PATCH 1/5] Handle return-during-throw in SEND --- Objects/genobject.c | 11 ++--------- Python/ceval.c | 7 +++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index 6551b939c4590c..18932991664fc1 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -485,15 +485,8 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, ret = _PyFrame_StackPop((_PyInterpreterFrame *)gen->gi_iframe); assert(ret == yf); Py_DECREF(ret); - /* Termination repetition of SEND loop */ - assert(frame->f_lasti >= 0); - PyObject *bytecode = gen->gi_code->co_code; - unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); - /* Backup to SEND */ - frame->f_lasti--; - assert(code[frame->f_lasti*sizeof(_Py_CODEUNIT)] == SEND); - int jump = code[frame->f_lasti*sizeof(_Py_CODEUNIT)+1]; - frame->f_lasti += jump; + // NULL tells SEND to quit sending: + _PyFrame_StackPush((_PyInterpreterFrame *)gen->gi_iframe, NULL); if (_PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send(gen, val); Py_DECREF(val); diff --git a/Python/ceval.c b/Python/ceval.c index 81759ad770b1e3..17b5045faa9e31 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2535,6 +2535,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int assert(STACK_LEVEL() >= 2); PyObject *v = POP(); PyObject *receiver = TOP(); + if (receiver == NULL) { + // Receiver completed during a throw() call. v is the return + // value: + SET_TOP(v); + JUMPBY(oparg); + DISPATCH(); + } PySendResult gen_status; PyObject *retval; if (tstate->c_tracefunc == NULL) { From dcf97b2e2a875e91c0a77fecb2a579cee1066586 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 17 Mar 2022 11:33:55 -0700 Subject: [PATCH 2/5] Update the docs for SEND --- Doc/library/dis.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 65e888dc86a194..1247a2cddbfa4a 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1272,10 +1272,17 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: SEND - - Sends ``None`` to the sub-generator of this generator. - Used in ``yield from`` and ``await`` statements. +.. opcode:: SEND (delta) + + Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` + statements. + + If the call raises :exc:`StopIteration`, pop both values, push its return + value, and increment the bytecode counter by *delta*. + + If TOS1 is ``NULL`` (set when it raises :exc:`StopIteration` during a + ``throw()`` through the current frame), pop both values, push TOS (its + return value), and increment the bytecode counter by *delta*. .. versionadded:: 3.11 From fb649c73071b6c5f63e6ea81a238e50d2b0bbfa2 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 17 Mar 2022 11:40:50 -0700 Subject: [PATCH 3/5] blurb add --- .../Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst new file mode 100644 index 00000000000000..a71ba26c107d55 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst @@ -0,0 +1,3 @@ +When a sub-iterator returns a value during a ``throw()`` call, perform the +resulting jump during the next :opcode:`SEND` instruction (rather than as +part of the ``throw()`` implementation). From acdf9848aa39a904f6322160e4bf87a01fcebaae Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 17 Mar 2022 12:30:48 -0700 Subject: [PATCH 4/5] Clean things up a bit --- Doc/library/dis.rst | 4 ++-- Python/ceval.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1247a2cddbfa4a..4fcd6452a2cbc2 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1276,10 +1276,10 @@ iterations of the loop. Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` statements. - + If the call raises :exc:`StopIteration`, pop both values, push its return value, and increment the bytecode counter by *delta*. - + If TOS1 is ``NULL`` (set when it raises :exc:`StopIteration` during a ``throw()`` through the current frame), pop both values, push TOS (its return value), and increment the bytecode counter by *delta*. diff --git a/Python/ceval.c b/Python/ceval.c index 17b5045faa9e31..a921d384316b50 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2536,8 +2536,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *v = POP(); PyObject *receiver = TOP(); if (receiver == NULL) { - // Receiver completed during a throw() call. v is the return - // value: + // Receiver returned during a throw(). v is its return value: SET_TOP(v); JUMPBY(oparg); DISPATCH(); From 5aebc871e16938c5c2b40221147e9d545c89f211 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 8 Jun 2022 11:59:30 -0700 Subject: [PATCH 5/5] Minor doc edits --- Doc/library/dis.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 5c06461a4b9479..5a62193185e126 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1321,12 +1321,15 @@ iterations of the loop. If the call raises :exc:`StopIteration`, pop both values, push its return value, and increment the bytecode counter by *delta*. - If TOS1 is ``NULL`` (set when it raises :exc:`StopIteration` during a - ``throw()`` through the current frame), pop both values, push TOS (its - return value), and increment the bytecode counter by *delta*. + If TOS1 is ``NULL`` (set when a ``throw()`` through the current frame + returns), pop both values, push TOS (its return value) back, and increment + the bytecode counter by *delta*. .. versionadded:: 3.11 + .. versionchanged:: 3.12 + Added ``NULL`` handling for subiterators that return during ``throw()``. + .. opcode:: ASYNC_GEN_WRAP