From ea2ae026078b328ddeab060940568a4d3bf1b417 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 15 Apr 2022 20:19:24 +0100 Subject: gh-91276: Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative (GH-32215) --- Doc/library/dis.rst | 13 +++++++++---- Doc/whatsnew/3.11.rst | 3 +++ Include/opcode.h | 2 +- Lib/importlib/_bootstrap_external.py | 4 +++- Lib/opcode.py | 4 ++-- .../2022-03-31-14-33-48.bpo-47120.6S_uoU.rst | 1 + Python/ceval.c | 8 ++++---- Python/compile.c | 15 +++++++++++++++ 8 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 657778c..08e6c73 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -993,21 +993,26 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: JUMP_IF_TRUE_OR_POP (target) +.. opcode:: JUMP_IF_TRUE_OR_POP (delta) - If TOS is true, sets the bytecode counter to *target* and leaves TOS on the + If TOS is true, increments the bytecode counter by *delta* and leaves TOS on the stack. Otherwise (TOS is false), TOS is popped. .. versionadded:: 3.1 + .. versionchanged:: 3.11 + The oparg is now a relative delta rather than an absolute target. -.. opcode:: JUMP_IF_FALSE_OR_POP (target) +.. opcode:: JUMP_IF_FALSE_OR_POP (delta) - If TOS is false, sets the bytecode counter to *target* and leaves TOS on the + If TOS is false, increments the bytecode counter by *delta* and leaves TOS on the stack. Otherwise (TOS is true), TOS is popped. .. versionadded:: 3.1 + .. versionchanged:: 3.11 + The oparg is now a relative delta rather than an absolute target. + .. opcode:: FOR_ITER (delta) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index b6f47f5..ca76efc 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -787,6 +787,9 @@ CPython bytecode changes :opcode:`POP_JUMP_FORWARD_IF_NONE` and :opcode:`POP_JUMP_BACKWARD_IF_NONE` opcodes to speed up conditional jumps. +* :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP` are now + relative rather than absolute. + Deprecated ========== diff --git a/Include/opcode.h b/Include/opcode.h index 0badf78..8db4238 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -199,7 +199,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 0U, 536870912U, - 135020544U, + 135118848U, 4163U, 122880U, 0U, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index d580e54..4eece8d 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -401,6 +401,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a6 3491 (remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH, # add JUMP_BACKWARD_NO_INTERRUPT, make JUMP_NO_INTERRUPT virtual) # Python 3.11a7 3492 (make POP_JUMP_IF_NONE/NOT_NONE/TRUE/FALSE relative) +# Python 3.11a7 3493 (Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative) # Python 3.12 will start with magic number 3500 @@ -415,7 +416,8 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3492).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3493).to_bytes(2, 'little') + b'\r\n' + _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index ee9effb..9ee0683 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -131,8 +131,8 @@ hascompare.append(107) name_op('IMPORT_NAME', 108) # Index in name list name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of words to skip -jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code -jabs_op('JUMP_IF_TRUE_OR_POP', 112) # "" +jrel_op('JUMP_IF_FALSE_OR_POP', 111) # Number of words to skip +jrel_op('JUMP_IF_TRUE_OR_POP', 112) # "" jrel_op('POP_JUMP_FORWARD_IF_FALSE', 114) jrel_op('POP_JUMP_FORWARD_IF_TRUE', 115) name_op('LOAD_GLOBAL', 116, 5) # Index in name list diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst new file mode 100644 index 0000000..c87d984 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst @@ -0,0 +1 @@ +Make opcodes :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP` relative rather than absolute. diff --git a/Python/ceval.c b/Python/ceval.c index 7891547..66856e5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4081,7 +4081,7 @@ handle_eval_breaker: DISPATCH(); } if (Py_IsFalse(cond)) { - JUMPTO(oparg); + JUMPBY(oparg); DISPATCH(); } err = PyObject_IsTrue(cond); @@ -4090,7 +4090,7 @@ handle_eval_breaker: Py_DECREF(cond); } else if (err == 0) - JUMPTO(oparg); + JUMPBY(oparg); else goto error; DISPATCH(); @@ -4105,12 +4105,12 @@ handle_eval_breaker: DISPATCH(); } if (Py_IsTrue(cond)) { - JUMPTO(oparg); + JUMPBY(oparg); DISPATCH(); } err = PyObject_IsTrue(cond); if (err > 0) { - JUMPTO(oparg); + JUMPBY(oparg); } else if (err == 0) { STACK_SHRINK(1); diff --git a/Python/compile.c b/Python/compile.c index 718b521..3b91566 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7672,6 +7672,21 @@ normalize_jumps(struct assembler *a) last->i_opcode = is_forward ? POP_JUMP_FORWARD_IF_TRUE : POP_JUMP_BACKWARD_IF_TRUE; break; + case JUMP_IF_TRUE_OR_POP: + case JUMP_IF_FALSE_OR_POP: + if (!is_forward) { + /* As far as we can tell, the compiler never emits + * these jumps with a backwards target. If/when this + * exception is raised, we have found a use case for + * a backwards version of this jump (or to replace + * it with the sequence (COPY 1, POP_JUMP_IF_T/F, POP) + */ + PyErr_Format(PyExc_SystemError, + "unexpected %s jumping backwards", + last->i_opcode == JUMP_IF_TRUE_OR_POP ? + "JUMP_IF_TRUE_OR_POP" : "JUMP_IF_FALSE_OR_POP"); + } + break; } } } -- cgit v0.12