]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-98831: rewrite PUSH_EXC_INFO and conditional jumps in the instruction definition...
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Wed, 1 Feb 2023 19:38:06 +0000 (19:38 +0000)
committerGitHub <noreply@github.com>
Wed, 1 Feb 2023 19:38:06 +0000 (19:38 +0000)
Python/bytecodes.c
Python/compile.c
Python/generated_cases.c.h
Python/opcode_metadata.h
Tools/cases_generator/generate_cases.py

index bb1deaf3fbeb4b133059a0fd89b71dde7c787cd4..105bd95be0fdc3bc32530a0a9e3552002284500c 100644 (file)
@@ -1898,9 +1898,7 @@ dummy_func(
             CHECK_EVAL_BREAKER();
         }
 
-        // stack effect: (__0 -- )
-        inst(POP_JUMP_IF_FALSE) {
-            PyObject *cond = POP();
+        inst(POP_JUMP_IF_FALSE, (cond -- )) {
             if (Py_IsTrue(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
@@ -1911,19 +1909,16 @@ dummy_func(
             else {
                 int err = PyObject_IsTrue(cond);
                 Py_DECREF(cond);
-                if (err > 0)
-                    ;
-                else if (err == 0) {
+                if (err == 0) {
                     JUMPBY(oparg);
                 }
-                else
-                    goto error;
+                else {
+                    ERROR_IF(err < 0, error);
+                }
             }
         }
 
-        // stack effect: (__0 -- )
-        inst(POP_JUMP_IF_TRUE) {
-            PyObject *cond = POP();
+        inst(POP_JUMP_IF_TRUE, (cond -- )) {
             if (Py_IsFalse(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
@@ -1937,25 +1932,23 @@ dummy_func(
                 if (err > 0) {
                     JUMPBY(oparg);
                 }
-                else if (err == 0)
-                    ;
-                else
-                    goto error;
+                else {
+                    ERROR_IF(err < 0, error);
+                }
             }
         }
 
-        // stack effect: (__0 -- )
-        inst(POP_JUMP_IF_NOT_NONE) {
-            PyObject *value = POP();
+        inst(POP_JUMP_IF_NOT_NONE, (value -- )) {
             if (!Py_IsNone(value)) {
+                Py_DECREF(value);
                 JUMPBY(oparg);
             }
-            Py_DECREF(value);
+            else {
+                _Py_DECREF_NO_DEALLOC(value);
+            }
         }
 
-        // stack effect: (__0 -- )
-        inst(POP_JUMP_IF_NONE) {
-            PyObject *value = POP();
+        inst(POP_JUMP_IF_NONE, (value -- )) {
             if (Py_IsNone(value)) {
                 _Py_DECREF_NO_DEALLOC(value);
                 JUMPBY(oparg);
@@ -1965,25 +1958,24 @@ dummy_func(
             }
         }
 
-        // error: JUMP_IF_FALSE_OR_POP stack effect depends on jump flag
-        inst(JUMP_IF_FALSE_OR_POP) {
-            PyObject *cond = TOP();
+        inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) {
+            bool jump = false;
             int err;
             if (Py_IsTrue(cond)) {
-                STACK_SHRINK(1);
                 _Py_DECREF_NO_DEALLOC(cond);
             }
             else if (Py_IsFalse(cond)) {
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 err = PyObject_IsTrue(cond);
                 if (err > 0) {
-                    STACK_SHRINK(1);
                     Py_DECREF(cond);
                 }
                 else if (err == 0) {
                     JUMPBY(oparg);
+                    jump = true;
                 }
                 else {
                     goto error;
@@ -1991,24 +1983,23 @@ dummy_func(
             }
         }
 
-        // error: JUMP_IF_TRUE_OR_POP stack effect depends on jump flag
-        inst(JUMP_IF_TRUE_OR_POP) {
-            PyObject *cond = TOP();
+        inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) {
+            bool jump = false;
             int err;
             if (Py_IsFalse(cond)) {
-                STACK_SHRINK(1);
                 _Py_DECREF_NO_DEALLOC(cond);
             }
             else if (Py_IsTrue(cond)) {
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 err = PyObject_IsTrue(cond);
                 if (err > 0) {
                     JUMPBY(oparg);
+                    jump = true;
                 }
                 else if (err == 0) {
-                    STACK_SHRINK(1);
                     Py_DECREF(cond);
                 }
                 else {
@@ -2321,22 +2312,16 @@ dummy_func(
             ERROR_IF(res == NULL, error);
         }
 
-        // stack effect: ( -- __0)
-        inst(PUSH_EXC_INFO) {
-            PyObject *value = TOP();
-
+        inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) {
             _PyErr_StackItem *exc_info = tstate->exc_info;
             if (exc_info->exc_value != NULL) {
-                SET_TOP(exc_info->exc_value);
+                prev_exc = exc_info->exc_value;
             }
             else {
-                SET_TOP(Py_NewRef(Py_None));
+                prev_exc = Py_NewRef(Py_None);
             }
-
-            PUSH(Py_NewRef(value));
-            assert(PyExceptionInstance_Check(value));
-            exc_info->exc_value = value;
-
+            assert(PyExceptionInstance_Check(new_exc));
+            exc_info->exc_value = Py_NewRef(new_exc);
         }
 
         inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) {
index a11bcc79a6dd106d614019d3d24371c2cfde282a..d9ec68958972b5f42d13b68ebfbaed77b6f5578a 100644 (file)
@@ -8630,17 +8630,19 @@ opcode_metadata_is_sane(cfg_builder *g) {
             int opcode = instr->i_opcode;
             int oparg = instr->i_oparg;
             assert(opcode <= MAX_REAL_OPCODE);
-            int popped = _PyOpcode_num_popped(opcode, oparg);
-            int pushed = _PyOpcode_num_pushed(opcode, oparg);
-            assert((pushed < 0) == (popped < 0));
-            if (pushed >= 0) {
-                assert(_PyOpcode_opcode_metadata[opcode].valid_entry);
-                int effect = stack_effect(opcode, instr->i_oparg, -1);
-                if (effect != pushed - popped) {
-                   fprintf(stderr,
-                           "op=%d: stack_effect (%d) != pushed (%d) - popped (%d)\n",
-                           opcode, effect, pushed, popped);
-                   result = false;
+            for (int jump = 0; jump <= 1; jump++) {
+                int popped = _PyOpcode_num_popped(opcode, oparg, jump ? true : false);
+                int pushed = _PyOpcode_num_pushed(opcode, oparg, jump ? true : false);
+                assert((pushed < 0) == (popped < 0));
+                if (pushed >= 0) {
+                    assert(_PyOpcode_opcode_metadata[opcode].valid_entry);
+                    int effect = stack_effect(opcode, instr->i_oparg, jump);
+                    if (effect != pushed - popped) {
+                       fprintf(stderr,
+                               "op=%d arg=%d jump=%d: stack_effect (%d) != pushed (%d) - popped (%d)\n",
+                               opcode, oparg, jump, effect, pushed, popped);
+                       result = false;
+                    }
                 }
             }
         }
index e5c5c7e557a37c6e107bae3982486b34df3e39a2..a02d8d79c60d37758dfb106d11c4dc59d9346275 100644 (file)
 
         TARGET(POP_JUMP_IF_FALSE) {
             PREDICTED(POP_JUMP_IF_FALSE);
-            PyObject *cond = POP();
+            PyObject *cond = PEEK(1);
             if (Py_IsTrue(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
             else {
                 int err = PyObject_IsTrue(cond);
                 Py_DECREF(cond);
-                if (err > 0)
-                    ;
-                else if (err == 0) {
+                if (err == 0) {
                     JUMPBY(oparg);
                 }
-                else
-                    goto error;
+                else {
+                    if (err < 0) goto pop_1_error;
+                }
             }
+            STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_TRUE) {
-            PyObject *cond = POP();
+            PyObject *cond = PEEK(1);
             if (Py_IsFalse(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
                 if (err > 0) {
                     JUMPBY(oparg);
                 }
-                else if (err == 0)
-                    ;
-                else
-                    goto error;
+                else {
+                    if (err < 0) goto pop_1_error;
+                }
             }
+            STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_NOT_NONE) {
-            PyObject *value = POP();
+            PyObject *value = PEEK(1);
             if (!Py_IsNone(value)) {
+                Py_DECREF(value);
                 JUMPBY(oparg);
             }
-            Py_DECREF(value);
+            else {
+                _Py_DECREF_NO_DEALLOC(value);
+            }
+            STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_NONE) {
-            PyObject *value = POP();
+            PyObject *value = PEEK(1);
             if (Py_IsNone(value)) {
                 _Py_DECREF_NO_DEALLOC(value);
                 JUMPBY(oparg);
             else {
                 Py_DECREF(value);
             }
+            STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(JUMP_IF_FALSE_OR_POP) {
-            PyObject *cond = TOP();
+            PyObject *cond = PEEK(1);
+            bool jump = false;
             int err;
             if (Py_IsTrue(cond)) {
-                STACK_SHRINK(1);
                 _Py_DECREF_NO_DEALLOC(cond);
             }
             else if (Py_IsFalse(cond)) {
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 err = PyObject_IsTrue(cond);
                 if (err > 0) {
-                    STACK_SHRINK(1);
                     Py_DECREF(cond);
                 }
                 else if (err == 0) {
                     JUMPBY(oparg);
+                    jump = true;
                 }
                 else {
                     goto error;
                 }
             }
+            STACK_SHRINK(1);
+            STACK_GROW((jump ? 1 : 0));
             DISPATCH();
         }
 
         TARGET(JUMP_IF_TRUE_OR_POP) {
-            PyObject *cond = TOP();
+            PyObject *cond = PEEK(1);
+            bool jump = false;
             int err;
             if (Py_IsFalse(cond)) {
-                STACK_SHRINK(1);
                 _Py_DECREF_NO_DEALLOC(cond);
             }
             else if (Py_IsTrue(cond)) {
                 JUMPBY(oparg);
+                jump = true;
             }
             else {
                 err = PyObject_IsTrue(cond);
                 if (err > 0) {
                     JUMPBY(oparg);
+                    jump = true;
                 }
                 else if (err == 0) {
-                    STACK_SHRINK(1);
                     Py_DECREF(cond);
                 }
                 else {
                     goto error;
                 }
             }
+            STACK_SHRINK(1);
+            STACK_GROW((jump ? 1 : 0));
             DISPATCH();
         }
 
         }
 
         TARGET(PUSH_EXC_INFO) {
-            PyObject *value = TOP();
-
+            PyObject *new_exc = PEEK(1);
+            PyObject *prev_exc;
             _PyErr_StackItem *exc_info = tstate->exc_info;
             if (exc_info->exc_value != NULL) {
-                SET_TOP(exc_info->exc_value);
+                prev_exc = exc_info->exc_value;
             }
             else {
-                SET_TOP(Py_NewRef(Py_None));
+                prev_exc = Py_NewRef(Py_None);
             }
-
-            PUSH(Py_NewRef(value));
-            assert(PyExceptionInstance_Check(value));
-            exc_info->exc_value = value;
+            assert(PyExceptionInstance_Check(new_exc));
+            exc_info->exc_value = Py_NewRef(new_exc);
+            STACK_GROW(1);
+            POKE(1, new_exc);
+            POKE(2, prev_exc);
             DISPATCH();
         }
 
index 96e57be8cf5deaa661c2448482737b4c2e2ebea4..c9f9759e16b316ec6c79802ba35eaf6273f4eb37 100644 (file)
@@ -4,7 +4,7 @@
 
 #ifndef NDEBUG
 static int
-_PyOpcode_num_popped(int opcode, int oparg) {
+_PyOpcode_num_popped(int opcode, int oparg, bool jump) {
     switch(opcode) {
         case NOP:
             return 0;
@@ -233,17 +233,17 @@ _PyOpcode_num_popped(int opcode, int oparg) {
         case JUMP_BACKWARD:
             return 0;
         case POP_JUMP_IF_FALSE:
-            return -1;
+            return 1;
         case POP_JUMP_IF_TRUE:
-            return -1;
+            return 1;
         case POP_JUMP_IF_NOT_NONE:
-            return -1;
+            return 1;
         case POP_JUMP_IF_NONE:
-            return -1;
+            return 1;
         case JUMP_IF_FALSE_OR_POP:
-            return -1;
+            return 1;
         case JUMP_IF_TRUE_OR_POP:
-            return -1;
+            return 1;
         case JUMP_BACKWARD_NO_INTERRUPT:
             return 0;
         case GET_LEN:
@@ -277,7 +277,7 @@ _PyOpcode_num_popped(int opcode, int oparg) {
         case WITH_EXCEPT_START:
             return 4;
         case PUSH_EXC_INFO:
-            return -1;
+            return 1;
         case LOAD_ATTR_METHOD_WITH_VALUES:
             return 1;
         case LOAD_ATTR_METHOD_NO_DICT:
@@ -350,7 +350,7 @@ _PyOpcode_num_popped(int opcode, int oparg) {
 
 #ifndef NDEBUG
 static int
-_PyOpcode_num_pushed(int opcode, int oparg) {
+_PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
     switch(opcode) {
         case NOP:
             return 0;
@@ -579,17 +579,17 @@ _PyOpcode_num_pushed(int opcode, int oparg) {
         case JUMP_BACKWARD:
             return 0;
         case POP_JUMP_IF_FALSE:
-            return -1;
+            return 0;
         case POP_JUMP_IF_TRUE:
-            return -1;
+            return 0;
         case POP_JUMP_IF_NOT_NONE:
-            return -1;
+            return 0;
         case POP_JUMP_IF_NONE:
-            return -1;
+            return 0;
         case JUMP_IF_FALSE_OR_POP:
-            return -1;
+            return (jump ? 1 : 0);
         case JUMP_IF_TRUE_OR_POP:
-            return -1;
+            return (jump ? 1 : 0);
         case JUMP_BACKWARD_NO_INTERRUPT:
             return 0;
         case GET_LEN:
@@ -623,7 +623,7 @@ _PyOpcode_num_pushed(int opcode, int oparg) {
         case WITH_EXCEPT_START:
             return 5;
         case PUSH_EXC_INFO:
-            return -1;
+            return 2;
         case LOAD_ATTR_METHOD_WITH_VALUES:
             return ((oparg & 1) ? 1 : 0) + 1;
         case LOAD_ATTR_METHOD_NO_DICT:
index 43685450cc0dfe1e57fd8c6be9b8d3ae98635fd2..3925583b40e728e3043b357ad2359a24b1e233b1 100644 (file)
@@ -868,7 +868,7 @@ class Analyzer:
         ) -> None:
             self.out.emit("\n#ifndef NDEBUG")
             self.out.emit("static int")
-            self.out.emit(f"_PyOpcode_num_{direction}(int opcode, int oparg) {{")
+            self.out.emit(f"_PyOpcode_num_{direction}(int opcode, int oparg, bool jump) {{")
             self.out.emit("    switch(opcode) {")
             for instr, effect in data:
                 self.out.emit(f"        case {instr.name}:")