From 4cfb59138338d20f750ea599e05391cdce0250bb Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 31 Mar 2022 15:27:52 +0100 Subject: [PATCH 1/3] bpo-47120: Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative --- Doc/library/dis.rst | 13 +++++++++---- Doc/whatsnew/3.11.rst | 3 +++ Include/opcode.h | 2 +- Lib/importlib/_bootstrap_external.py | 3 ++- Lib/opcode.py | 6 +++--- Python/ceval.c | 8 ++++---- 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index d1a0cecd82841f..f571e75891a3c8 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -965,21 +965,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:: JUMP_NO_INTERRUPT (target) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 1bd958724f3be7..aa38b12f486b77 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -524,6 +524,9 @@ CPython bytecode changes * Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. +* :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 3a7db438ede1f3..2b9b7f1a20b5e3 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -195,7 +195,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 0U, 536870912U, - 134234112U, + 134332416U, 4096U, 0U, 0U, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 744fefd5e21e79..5a5b52eac089c7 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -397,6 +397,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism) # Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL) # Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE) +# Python 3.11a6 3490 (Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative) # Python 3.12 will start with magic number 3500 @@ -411,7 +412,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3489).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3490).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 6bc64177ac8fc6..916598573f2a76 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -129,9 +129,9 @@ def jabs_op(name, op, entries=0): 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) # "" -jabs_op('POP_JUMP_IF_FALSE', 114) # "" +jrel_op('JUMP_IF_FALSE_OR_POP', 111) # Number of words to skip +jrel_op('JUMP_IF_TRUE_OR_POP', 112) # "" +jabs_op('POP_JUMP_IF_FALSE', 114) # Target byte offset from beginning of code jabs_op('POP_JUMP_IF_TRUE', 115) # "" name_op('LOAD_GLOBAL', 116, 5) # Index in name list def_op('IS_OP', 117) diff --git a/Python/ceval.c b/Python/ceval.c index 8f73ea1c01ac5d..e0d716e6f89625 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4018,7 +4018,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } if (Py_IsFalse(cond)) { - JUMPTO(oparg); + JUMPBY(oparg); DISPATCH(); } err = PyObject_IsTrue(cond); @@ -4027,7 +4027,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int Py_DECREF(cond); } else if (err == 0) - JUMPTO(oparg); + JUMPBY(oparg); else goto error; DISPATCH(); @@ -4042,12 +4042,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int 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); From ee571451c69426b103bfcb1f4ac7a2c6ab9293fd Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 14:33:50 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-31-14-33-48.bpo-47120.6S_uoU.rst 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 00000000000000..c87d9843d9157d --- /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. From dbb2fd636187763a49cf58675b4c857e1865304f Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 11 Apr 2022 19:45:26 +0100 Subject: [PATCH 3/3] raise SystemError if our assumption about these jumps always being forward turns out wrong --- Python/compile.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index 38cf5f362705a7..0ed4dec7e4c202 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; } } }