[Python-checkins] gh-98831: rewrite SEND, GET_YIELD_FROM_ITER, RETURN_GENERATOR in the instruction definition DSL (#101516)

iritkatriel webhook-mailer at python.org
Fri Feb 3 06:30:27 EST 2023


https://github.com/python/cpython/commit/04e06e20ee61f3c0d1d7a827b2feb4ed41bb198d
commit: 04e06e20ee61f3c0d1d7a827b2feb4ed41bb198d
branch: main
author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com>
date: 2023-02-03T11:30:21Z
summary:

gh-98831: rewrite SEND, GET_YIELD_FROM_ITER, RETURN_GENERATOR in the instruction definition DSL (#101516)

files:
M Python/bytecodes.c
M Python/generated_cases.c.h
M Python/opcode_metadata.h

diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 169a2647866b..74c53ad1579f 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -663,14 +663,10 @@ dummy_func(
             PREDICT(LOAD_CONST);
         }
 
-        // error: SEND stack effect depends on jump flag
-        inst(SEND) {
+        inst(SEND, (receiver, v -- receiver if (!jump), retval)) {
             assert(frame != &entry_frame);
-            assert(STACK_LEVEL() >= 2);
-            PyObject *v = POP();
-            PyObject *receiver = TOP();
+            bool jump = false;
             PySendResult gen_status;
-            PyObject *retval;
             if (tstate->c_tracefunc == NULL) {
                 gen_status = PyIter_Send(receiver, v, &retval);
             } else {
@@ -695,21 +691,20 @@ dummy_func(
                     gen_status = PYGEN_NEXT;
                 }
             }
-            Py_DECREF(v);
             if (gen_status == PYGEN_ERROR) {
                 assert(retval == NULL);
                 goto error;
             }
+            Py_DECREF(v);
             if (gen_status == PYGEN_RETURN) {
                 assert(retval != NULL);
                 Py_DECREF(receiver);
-                SET_TOP(retval);
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 assert(gen_status == PYGEN_NEXT);
                 assert(retval != NULL);
-                PUSH(retval);
             }
         }
 
@@ -2043,31 +2038,30 @@ dummy_func(
             ERROR_IF(iter == NULL, error);
         }
 
-        // stack effect: ( -- )
-        inst(GET_YIELD_FROM_ITER) {
+        inst(GET_YIELD_FROM_ITER, (iterable -- iter)) {
             /* before: [obj]; after [getiter(obj)] */
-            PyObject *iterable = TOP();
-            PyObject *iter;
             if (PyCoro_CheckExact(iterable)) {
                 /* `iterable` is a coroutine */
                 if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
                     /* and it is used in a 'yield from' expression of a
                        regular generator. */
-                    Py_DECREF(iterable);
-                    SET_TOP(NULL);
                     _PyErr_SetString(tstate, PyExc_TypeError,
                                      "cannot 'yield from' a coroutine object "
                                      "in a non-coroutine generator");
                     goto error;
                 }
+                iter = iterable;
+            }
+            else if (PyGen_CheckExact(iterable)) {
+                iter = iterable;
             }
-            else if (!PyGen_CheckExact(iterable)) {
+            else {
                 /* `iterable` is not a generator. */
                 iter = PyObject_GetIter(iterable);
-                Py_DECREF(iterable);
-                SET_TOP(iter);
-                if (iter == NULL)
+                if (iter == NULL) {
                     goto error;
+                }
+                Py_DECREF(iterable);
             }
             PREDICT(LOAD_CONST);
         }
@@ -3010,8 +3004,7 @@ dummy_func(
             PUSH((PyObject *)func);
         }
 
-        // stack effect: ( -- )
-        inst(RETURN_GENERATOR) {
+        inst(RETURN_GENERATOR, (--)) {
             assert(PyFunction_Check(frame->f_funcobj));
             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 97263866fe91..6f90d9ca4a59 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -865,12 +865,12 @@
         }
 
         TARGET(SEND) {
+            PyObject *v = PEEK(1);
+            PyObject *receiver = PEEK(2);
+            PyObject *retval;
             assert(frame != &entry_frame);
-            assert(STACK_LEVEL() >= 2);
-            PyObject *v = POP();
-            PyObject *receiver = TOP();
+            bool jump = false;
             PySendResult gen_status;
-            PyObject *retval;
             if (tstate->c_tracefunc == NULL) {
                 gen_status = PyIter_Send(receiver, v, &retval);
             } else {
@@ -895,22 +895,24 @@
                     gen_status = PYGEN_NEXT;
                 }
             }
-            Py_DECREF(v);
             if (gen_status == PYGEN_ERROR) {
                 assert(retval == NULL);
                 goto error;
             }
+            Py_DECREF(v);
             if (gen_status == PYGEN_RETURN) {
                 assert(retval != NULL);
                 Py_DECREF(receiver);
-                SET_TOP(retval);
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 assert(gen_status == PYGEN_NEXT);
                 assert(retval != NULL);
-                PUSH(retval);
             }
+            STACK_SHRINK(1);
+            STACK_GROW(((!jump) ? 1 : 0));
+            POKE(1, retval);
             DISPATCH();
         }
 
@@ -2584,30 +2586,33 @@
         }
 
         TARGET(GET_YIELD_FROM_ITER) {
-            /* before: [obj]; after [getiter(obj)] */
-            PyObject *iterable = TOP();
+            PyObject *iterable = PEEK(1);
             PyObject *iter;
+            /* before: [obj]; after [getiter(obj)] */
             if (PyCoro_CheckExact(iterable)) {
                 /* `iterable` is a coroutine */
                 if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
                     /* and it is used in a 'yield from' expression of a
                        regular generator. */
-                    Py_DECREF(iterable);
-                    SET_TOP(NULL);
                     _PyErr_SetString(tstate, PyExc_TypeError,
                                      "cannot 'yield from' a coroutine object "
                                      "in a non-coroutine generator");
                     goto error;
                 }
+                iter = iterable;
             }
-            else if (!PyGen_CheckExact(iterable)) {
+            else if (PyGen_CheckExact(iterable)) {
+                iter = iterable;
+            }
+            else {
                 /* `iterable` is not a generator. */
                 iter = PyObject_GetIter(iterable);
-                Py_DECREF(iterable);
-                SET_TOP(iter);
-                if (iter == NULL)
+                if (iter == NULL) {
                     goto error;
+                }
+                Py_DECREF(iterable);
             }
+            POKE(1, iter);
             PREDICT(LOAD_CONST);
             DISPATCH();
         }
diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h
index ca3dde363bfd..256f81a89fcd 100644
--- a/Python/opcode_metadata.h
+++ b/Python/opcode_metadata.h
@@ -99,7 +99,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
         case GET_AWAITABLE:
             return 1;
         case SEND:
-            return -1;
+            return 2;
         case YIELD_VALUE:
             return 1;
         case POP_EXCEPT:
@@ -259,7 +259,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
         case GET_ITER:
             return 1;
         case GET_YIELD_FROM_ITER:
-            return -1;
+            return 1;
         case FOR_ITER:
             return -1;
         case FOR_ITER_LIST:
@@ -327,7 +327,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
         case MAKE_FUNCTION:
             return -1;
         case RETURN_GENERATOR:
-            return -1;
+            return 0;
         case BUILD_SLICE:
             return -1;
         case FORMAT_VALUE:
@@ -445,7 +445,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
         case GET_AWAITABLE:
             return 1;
         case SEND:
-            return -1;
+            return ((!jump) ? 1 : 0) + 1;
         case YIELD_VALUE:
             return 1;
         case POP_EXCEPT:
@@ -605,7 +605,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
         case GET_ITER:
             return 1;
         case GET_YIELD_FROM_ITER:
-            return -1;
+            return 1;
         case FOR_ITER:
             return -1;
         case FOR_ITER_LIST:
@@ -673,7 +673,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
         case MAKE_FUNCTION:
             return -1;
         case RETURN_GENERATOR:
-            return -1;
+            return 0;
         case BUILD_SLICE:
             return -1;
         case FORMAT_VALUE:



More information about the Python-checkins mailing list