]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-98831: rewrite SEND, GET_YIELD_FROM_ITER, RETURN_GENERATOR in the instruction...
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Fri, 3 Feb 2023 11:30:21 +0000 (11:30 +0000)
committerGitHub <noreply@github.com>
Fri, 3 Feb 2023 11:30:21 +0000 (11:30 +0000)
Python/bytecodes.c
Python/generated_cases.c.h
Python/opcode_metadata.h

index 169a2647866b313707b3a265bf737727152fcf95..74c53ad1579f6c497af64fe7e50111ae73b4e0dd 100644 (file)
@@ -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);
index 97263866fe91585e40f4a0e826cb37a132732f30..6f90d9ca4a59ef047881120c1afc1b0c5c165eec 100644 (file)
         }
 
         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 {
                     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();
         }
 
         }
 
         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();
         }
index ca3dde363bfd854fff13cf73008334d11da4bf26..256f81a89fcd3688478d623ab7e6740a1b3d6637 100644 (file)
@@ -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: