From dd207a6ac52d4bd9a71cf178fc1d5c17a6f07aff Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:40:24 +0100 Subject: [PATCH] bpo-47120: make POP_JUMP_IF_TRUE/FALSE/NONE/NOT_NONE relative (GH-32400) --- Doc/library/dis.rst | 64 +++++-- Doc/whatsnew/3.11.rst | 15 +- Include/opcode.h | 38 ++-- Lib/dis.py | 7 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 13 +- Lib/test/test_dis.py | 28 ++- Lib/test/test_peepholer.py | 9 +- .../2022-04-06-22-50-31.bpo-47120.mbfHs5.rst | 1 + Objects/frameobject.c | 14 +- Python/ceval.c | 179 +++++++++++++----- Python/compile.c | 91 +++++++-- Python/opcode_targets.h | 16 +- Python/specialize.c | 14 +- 14 files changed, 357 insertions(+), 135 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index fa0e23a6c96..657778c0f40 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -937,30 +937,58 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: POP_JUMP_IF_TRUE (target) +.. opcode:: POP_JUMP_FORWARD_IF_TRUE (delta) - If TOS is true, sets the bytecode counter to *target*. TOS is popped. - - .. versionadded:: 3.1 - - -.. opcode:: POP_JUMP_IF_FALSE (target) - - If TOS is false, sets the bytecode counter to *target*. TOS is popped. - - .. versionadded:: 3.1 - - -.. opcode:: POP_JUMP_IF_NOT_NONE (target) - - If TOS is not none, sets the bytecode counter to *target*. TOS is popped. + If TOS is true, increments the bytecode counter by *delta*. TOS is popped. .. versionadded:: 3.11 -.. opcode:: POP_JUMP_IF_NONE (target) +.. opcode:: POP_JUMP_BACKWARD_IF_TRUE (delta) - If TOS is none, sets the bytecode counter to *target*. TOS is popped. + If TOS is true, decrements the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_FORWARD_IF_FALSE (delta) + + If TOS is false, increments the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_BACKWARD_IF_FALSE (delta) + + If TOS is false, decrements the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_FORWARD_IF_NOT_NONE (delta) + + If TOS is not ``None``, increments the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_BACKWARD_IF_NOT_NONE (delta) + + If TOS is not ``None``, decrements the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_FORWARD_IF_NONE (delta) + + If TOS is ``None``, increments the bytecode counter by *delta*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_BACKWARD_IF_NONE (delta) + + If TOS is ``None``, decrements the bytecode counter by *delta*. TOS is popped. .. versionadded:: 3.11 diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 870330c5796..df0b0a7fbeb 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -750,9 +750,6 @@ CPython bytecode changes ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) with new :opcode:`COPY` and :opcode:`SWAP` instructions. -* Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to - speed up conditional jumps. - * Replaced :opcode:`JUMP_IF_NOT_EXC_MATCH` by :opcode:`CHECK_EXC_MATCH` which performs the check but does not jump. @@ -761,7 +758,17 @@ CPython bytecode changes * Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. -* Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it is undesirable to handle interrupts. +* Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it + is undesirable to handle interrupts. + +* Replaced :opcode:`POP_JUMP_IF_TRUE` and :opcode:`POP_JUMP_IF_FALSE` by + the relative :opcode:`POP_JUMP_FORWARD_IF_TRUE`, :opcode:`POP_JUMP_BACKWARD_IF_TRUE`, + :opcode:`POP_JUMP_FORWARD_IF_FALSE` and :opcode:`POP_JUMP_BACKWARD_IF_FALSE`. + +* Added :opcode:`POP_JUMP_FORWARD_IF_NOT_NONE`, :opcode:`POP_JUMP_BACKWARD_IF_NOT_NONE`, + :opcode:`POP_JUMP_FORWARD_IF_NONE` and :opcode:`POP_JUMP_BACKWARD_IF_NONE` + opcodes to speed up conditional jumps. + Deprecated ========== diff --git a/Include/opcode.h b/Include/opcode.h index ff3ffddda21..57a72a6e892 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -69,8 +69,8 @@ extern "C" { #define JUMP_FORWARD 110 #define JUMP_IF_FALSE_OR_POP 111 #define JUMP_IF_TRUE_OR_POP 112 -#define POP_JUMP_IF_FALSE 114 -#define POP_JUMP_IF_TRUE 115 +#define POP_JUMP_FORWARD_IF_FALSE 114 +#define POP_JUMP_FORWARD_IF_TRUE 115 #define LOAD_GLOBAL 116 #define IS_OP 117 #define CONTAINS_OP 118 @@ -81,8 +81,8 @@ extern "C" { #define LOAD_FAST 124 #define STORE_FAST 125 #define DELETE_FAST 126 -#define POP_JUMP_IF_NOT_NONE 128 -#define POP_JUMP_IF_NONE 129 +#define POP_JUMP_FORWARD_IF_NOT_NONE 128 +#define POP_JUMP_FORWARD_IF_NONE 129 #define RAISE_VARARGS 130 #define GET_AWAITABLE 131 #define MAKE_FUNCTION 132 @@ -114,6 +114,10 @@ extern "C" { #define PRECALL 166 #define CALL 171 #define KW_NAMES 172 +#define POP_JUMP_BACKWARD_IF_NOT_NONE 173 +#define POP_JUMP_BACKWARD_IF_NONE 174 +#define POP_JUMP_BACKWARD_IF_FALSE 175 +#define POP_JUMP_BACKWARD_IF_TRUE 176 #define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADD_FLOAT 4 #define BINARY_OP_ADD_INT 5 @@ -181,9 +185,9 @@ extern "C" { #define STORE_SUBSCR_DICT 168 #define STORE_SUBSCR_LIST_INT 169 #define UNPACK_SEQUENCE_ADAPTIVE 170 -#define UNPACK_SEQUENCE_LIST 173 -#define UNPACK_SEQUENCE_TUPLE 174 -#define UNPACK_SEQUENCE_TWO_TUPLE 175 +#define UNPACK_SEQUENCE_LIST 177 +#define UNPACK_SEQUENCE_TUPLE 178 +#define UNPACK_SEQUENCE_TWO_TUPLE 179 #define DO_TRACING 255 extern const uint8_t _PyOpcode_Caches[256]; @@ -195,9 +199,9 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 0U, 536870912U, - 134234112U, - 4160U, - 0U, + 135020544U, + 4163U, + 122880U, 0U, 0U, }; @@ -207,7 +211,7 @@ static const uint32_t _PyOpcode_Jump[8] = { 536870912U, 135118848U, 4163U, - 0U, + 122880U, 0U, 0U, }; @@ -338,10 +342,14 @@ const uint8_t _PyOpcode_Deopt[256] = { [MATCH_SEQUENCE] = MATCH_SEQUENCE, [NOP] = NOP, [POP_EXCEPT] = POP_EXCEPT, - [POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, - [POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, - [POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, - [POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE, + [POP_JUMP_BACKWARD_IF_FALSE] = POP_JUMP_BACKWARD_IF_FALSE, + [POP_JUMP_BACKWARD_IF_NONE] = POP_JUMP_BACKWARD_IF_NONE, + [POP_JUMP_BACKWARD_IF_NOT_NONE] = POP_JUMP_BACKWARD_IF_NOT_NONE, + [POP_JUMP_BACKWARD_IF_TRUE] = POP_JUMP_BACKWARD_IF_TRUE, + [POP_JUMP_FORWARD_IF_FALSE] = POP_JUMP_FORWARD_IF_FALSE, + [POP_JUMP_FORWARD_IF_NONE] = POP_JUMP_FORWARD_IF_NONE, + [POP_JUMP_FORWARD_IF_NOT_NONE] = POP_JUMP_FORWARD_IF_NOT_NONE, + [POP_JUMP_FORWARD_IF_TRUE] = POP_JUMP_FORWARD_IF_TRUE, [POP_TOP] = POP_TOP, [PRECALL] = PRECALL, [PRECALL_ADAPTIVE] = PRECALL, diff --git a/Lib/dis.py b/Lib/dis.py index d9936ce1a00..ac900d743a0 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -392,6 +392,9 @@ def parse_exception_table(code): except StopIteration: return entries +def _is_backward_jump(op): + return 'JUMP_BACKWARD' in opname[op] + def _get_instructions_bytes(code, varname_from_oparg=None, names=None, co_consts=None, linestarts=None, line_offset=0, @@ -442,7 +445,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, argval = arg*2 argrepr = "to " + repr(argval) elif op in hasjrel: - signed_arg = -arg if op == JUMP_BACKWARD else arg + signed_arg = -arg if _is_backward_jump(op) else arg argval = offset + 2 + signed_arg*2 argrepr = "to " + repr(argval) elif op in haslocal or op in hasfree: @@ -568,7 +571,7 @@ def findlabels(code): for offset, op, arg in _unpack_opargs(code): if arg is not None: if op in hasjrel: - if op == JUMP_BACKWARD: + if _is_backward_jump(op): arg = -arg label = offset + 2 + arg*2 elif op in hasjabs: diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 45be177df76..d580e541738 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -400,6 +400,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a6 3490 (remove JUMP_IF_NOT_EXC_MATCH, add CHECK_EXC_MATCH) # 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.12 will start with magic number 3500 @@ -414,7 +415,7 @@ _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 = (3491).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3492).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 97b580532cb..ee9effbe540 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -133,8 +133,8 @@ 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) # "" -jabs_op('POP_JUMP_IF_TRUE', 115) # "" +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 def_op('IS_OP', 117) def_op('CONTAINS_OP', 118) @@ -148,8 +148,8 @@ def_op('STORE_FAST', 125) # Local variable number haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) -jabs_op('POP_JUMP_IF_NOT_NONE', 128) -jabs_op('POP_JUMP_IF_NONE', 129) +jrel_op('POP_JUMP_FORWARD_IF_NOT_NONE', 128) +jrel_op('POP_JUMP_FORWARD_IF_NONE', 129) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('GET_AWAITABLE', 131) def_op('MAKE_FUNCTION', 132) # Flags @@ -197,6 +197,11 @@ def_op('CALL', 171, 4) def_op('KW_NAMES', 172) hasconst.append(172) +jrel_op('POP_JUMP_BACKWARD_IF_NOT_NONE', 173) +jrel_op('POP_JUMP_BACKWARD_IF_NONE', 174) +jrel_op('POP_JUMP_BACKWARD_IF_FALSE', 175) +jrel_op('POP_JUMP_BACKWARD_IF_TRUE', 176) + del def_op, name_op, jrel_op, jabs_op diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 2f78d42cc72..1703e711d56 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -373,7 +373,7 @@ dis_traceback = """\ %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 36 (to 72) + POP_JUMP_FORWARD_IF_FALSE 18 (to 72) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -685,7 +685,15 @@ class DisTests(DisTestBase): for opcode, opname in enumerate(dis.opname): if opname in ('BUILD_MAP_UNPACK_WITH_CALL', 'BUILD_TUPLE_UNPACK_WITH_CALL', - 'JUMP_BACKWARD_NO_INTERRUPT'): + 'JUMP_BACKWARD_NO_INTERRUPT', + 'POP_JUMP_FORWARD_IF_NONE', + 'POP_JUMP_BACKWARD_IF_NONE', + 'POP_JUMP_FORWARD_IF_NOT_NONE', + 'POP_JUMP_BACKWARD_IF_NOT_NONE', + 'POP_JUMP_FORWARD_IF_TRUE', + 'POP_JUMP_BACKWARD_IF_TRUE', + 'POP_JUMP_FORWARD_IF_FALSE', + 'POP_JUMP_BACKWARD_IF_FALSE'): continue with self.subTest(opname=opname): width = dis._OPNAME_WIDTH @@ -1227,12 +1235,12 @@ expected_opinfo_jumpy = [ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=40, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None), @@ -1242,7 +1250,7 @@ expected_opinfo_jumpy = [ Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=128, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=102, argval=204, argrepr='to 204', offset=130, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=36, argval=204, argrepr='to 204', offset=130, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=132, starts_line=12, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None), @@ -1255,15 +1263,15 @@ expected_opinfo_jumpy = [ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=93, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=100, argval=200, argrepr='to 200', offset=196, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=200, argrepr='to 200', offset=196, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=17, argval=234, argrepr='to 234', offset=198, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=200, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=66, argval=132, argrepr='to 132', offset=202, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_BACKWARD_IF_TRUE', opcode=176, arg=36, argval=132, argrepr='to 132', offset=202, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=204, starts_line=19, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=216, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), @@ -1291,7 +1299,7 @@ expected_opinfo_jumpy = [ Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=328, argrepr='to 328', offset=304, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=160, argval=320, argrepr='to 320', offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=320, argrepr='to 320', offset=310, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), @@ -1304,7 +1312,7 @@ expected_opinfo_jumpy = [ Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None), Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=192, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None), diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index ab715e2e8f6..6a2f550d670 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -76,8 +76,9 @@ class TestTranforms(BytecodeTestCase): if not x == 2: del x self.assertNotInBytecode(unot, 'UNARY_NOT') - self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE') - self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE') + self.assertNotInBytecode(unot, 'POP_JUMP_FORWARD_IF_FALSE') + self.assertNotInBytecode(unot, 'POP_JUMP_BACKWARD_IF_FALSE') + self.assertInBytecode(unot, 'POP_JUMP_FORWARD_IF_TRUE') self.check_lnotab(unot) def test_elim_inversion_of_is_or_in(self): @@ -405,7 +406,7 @@ class TestTranforms(BytecodeTestCase): self.check_lnotab(f) self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP') self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_FALSE') + self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_FALSE') # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump def f(a, b, c): return ((a or b) @@ -414,7 +415,7 @@ class TestTranforms(BytecodeTestCase): self.check_lnotab(f) self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP') self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_TRUE') + self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_TRUE') def test_elim_jump_after_return1(self): # Eliminate dead code: jumps immediately after returns can't be reached diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst new file mode 100644 index 00000000000..3afe8c2bb65 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst @@ -0,0 +1 @@ +Make :opcode:`POP_JUMP_IF_TRUE`, :opcode:`POP_JUMP_IF_FALSE`, :opcode:`POP_JUMP_IF_NONE` and :opcode:`POP_JUMP_IF_NOT_NONE` virtual, mapping to new relative jump opcodes. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 5bb89370098..7a4d2fac938 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -206,11 +206,21 @@ mark_stacks(PyCodeObject *code_obj, int len) switch (opcode) { case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: + case POP_JUMP_FORWARD_IF_FALSE: + case POP_JUMP_BACKWARD_IF_FALSE: + case POP_JUMP_FORWARD_IF_TRUE: + case POP_JUMP_BACKWARD_IF_TRUE: { int64_t target_stack; int j = get_arg(code, i); + if (opcode == POP_JUMP_FORWARD_IF_FALSE || + opcode == POP_JUMP_FORWARD_IF_TRUE) { + j += i + 1; + } + else if (opcode == POP_JUMP_BACKWARD_IF_FALSE || + opcode == POP_JUMP_BACKWARD_IF_TRUE) { + j = i + 1 - j; + } assert(j < len); if (stacks[j] == UNINITIALIZED && j < i) { todo = 1; diff --git a/Python/ceval.c b/Python/ceval.c index f3d1c100d83..b46b1ef8429 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3646,8 +3646,6 @@ handle_eval_breaker: goto error; } JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP); - PREDICT(POP_JUMP_IF_FALSE); - PREDICT(POP_JUMP_IF_TRUE); DISPATCH(); } @@ -3670,7 +3668,7 @@ handle_eval_breaker: TARGET(COMPARE_OP_FLOAT_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (float ? float) + POP_JUMP_IF_(true/false) + // Combined: COMPARE_OP (float ? float) + POP_JUMP_(direction)_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; int when_to_jump_mask = cache->mask; PyObject *right = TOP(); @@ -3688,22 +3686,31 @@ handle_eval_breaker: STACK_SHRINK(2); Py_DECREF(left); Py_DECREF(right); - assert(opcode == POP_JUMP_IF_TRUE || opcode == POP_JUMP_IF_FALSE); - int jump = (1 << (sign + 1)) & when_to_jump_mask; + assert(opcode == POP_JUMP_FORWARD_IF_FALSE || + opcode == POP_JUMP_BACKWARD_IF_FALSE || + opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_TRUE); + int jump = (9 << (sign + 1)) & when_to_jump_mask; if (!jump) { next_instr++; - NOTRACE_DISPATCH(); + } + else if (jump >= 8) { + assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_FALSE); + JUMPBY(1 - oparg); + CHECK_EVAL_BREAKER(); } else { - JUMPTO(oparg); - CHECK_EVAL_BREAKER(); - NOTRACE_DISPATCH(); + assert(opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_FORWARD_IF_FALSE); + JUMPBY(1 + oparg); } + NOTRACE_DISPATCH(); } TARGET(COMPARE_OP_INT_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (int ? int) + POP_JUMP_IF_(true/false) + // Combined: COMPARE_OP (int ? int) + POP_JUMP_(direction)_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; int when_to_jump_mask = cache->mask; PyObject *right = TOP(); @@ -3722,24 +3729,33 @@ handle_eval_breaker: STACK_SHRINK(2); Py_DECREF(left); Py_DECREF(right); - assert(opcode == POP_JUMP_IF_TRUE || opcode == POP_JUMP_IF_FALSE); - int jump = (1 << (sign + 1)) & when_to_jump_mask; + assert(opcode == POP_JUMP_FORWARD_IF_FALSE || + opcode == POP_JUMP_BACKWARD_IF_FALSE || + opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_TRUE); + int jump = (9 << (sign + 1)) & when_to_jump_mask; if (!jump) { next_instr++; - NOTRACE_DISPATCH(); + } + else if (jump >= 8) { + assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_FALSE); + JUMPBY(1 - oparg); + CHECK_EVAL_BREAKER(); } else { - JUMPTO(oparg); - CHECK_EVAL_BREAKER(); - NOTRACE_DISPATCH(); + assert(opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_FORWARD_IF_FALSE); + JUMPBY(1 + oparg); } + NOTRACE_DISPATCH(); } TARGET(COMPARE_OP_STR_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (str == str or str != str) + POP_JUMP_IF_(true/false) + // Combined: COMPARE_OP (str == str or str != str) + POP_JUMP_(direction)_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; - int invert = cache->mask; + int when_to_jump_mask = cache->mask; PyObject *right = TOP(); PyObject *left = SECOND(); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); @@ -3752,22 +3768,31 @@ handle_eval_breaker: assert(oparg == Py_EQ || oparg == Py_NE); JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP); NEXTOPARG(); - assert(opcode == POP_JUMP_IF_TRUE || opcode == POP_JUMP_IF_FALSE); + assert(opcode == POP_JUMP_FORWARD_IF_FALSE || + opcode == POP_JUMP_BACKWARD_IF_FALSE || + opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_TRUE); STACK_SHRINK(2); Py_DECREF(left); Py_DECREF(right); assert(res == 0 || res == 1); - assert(invert == 0 || invert == 1); - int jump = res ^ invert; + int sign = 1 - res; + int jump = (9 << (sign + 1)) & when_to_jump_mask; if (!jump) { next_instr++; - NOTRACE_DISPATCH(); + } + else if (jump >= 8) { + assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || + opcode == POP_JUMP_BACKWARD_IF_FALSE); + JUMPBY(1 - oparg); + CHECK_EVAL_BREAKER(); } else { - JUMPTO(oparg); - CHECK_EVAL_BREAKER(); - NOTRACE_DISPATCH(); + assert(opcode == POP_JUMP_FORWARD_IF_TRUE || + opcode == POP_JUMP_FORWARD_IF_FALSE); + JUMPBY(1 + oparg); } + NOTRACE_DISPATCH(); } TARGET(IS_OP) { @@ -3779,8 +3804,6 @@ handle_eval_breaker: SET_TOP(b); Py_DECREF(left); Py_DECREF(right); - PREDICT(POP_JUMP_IF_FALSE); - PREDICT(POP_JUMP_IF_TRUE); DISPATCH(); } @@ -3796,8 +3819,6 @@ handle_eval_breaker: PyObject *b = (res^oparg) ? Py_True : Py_False; Py_INCREF(b); PUSH(b); - PREDICT(POP_JUMP_IF_FALSE); - PREDICT(POP_JUMP_IF_TRUE); DISPATCH(); } @@ -3915,26 +3936,25 @@ handle_eval_breaker: JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } - TARGET(POP_JUMP_IF_FALSE) { - PREDICTED(POP_JUMP_IF_FALSE); + TARGET(POP_JUMP_BACKWARD_IF_FALSE) { + PREDICTED(POP_JUMP_BACKWARD_IF_FALSE); PyObject *cond = POP(); - int err; if (Py_IsTrue(cond)) { Py_DECREF(cond); DISPATCH(); } if (Py_IsFalse(cond)) { Py_DECREF(cond); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } - err = PyObject_IsTrue(cond); + int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) ; else if (err == 0) { - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); } else @@ -3942,24 +3962,46 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_IF_TRUE) { - PREDICTED(POP_JUMP_IF_TRUE); + TARGET(POP_JUMP_FORWARD_IF_FALSE) { + PREDICTED(POP_JUMP_FORWARD_IF_FALSE); + PyObject *cond = POP(); + if (Py_IsTrue(cond)) { + Py_DECREF(cond); + } + else if (Py_IsFalse(cond)) { + Py_DECREF(cond); + JUMPBY(oparg); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) + ; + else if (err == 0) { + JUMPBY(oparg); + } + else + goto error; + } + DISPATCH(); + } + + TARGET(POP_JUMP_BACKWARD_IF_TRUE) { PyObject *cond = POP(); - int err; if (Py_IsFalse(cond)) { Py_DECREF(cond); DISPATCH(); } if (Py_IsTrue(cond)) { Py_DECREF(cond); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } - err = PyObject_IsTrue(cond); + int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) { - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); } else if (err == 0) @@ -3969,11 +4011,34 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_IF_NOT_NONE) { + TARGET(POP_JUMP_FORWARD_IF_TRUE) { + PyObject *cond = POP(); + if (Py_IsFalse(cond)) { + Py_DECREF(cond); + } + else if (Py_IsTrue(cond)) { + Py_DECREF(cond); + JUMPBY(oparg); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) { + JUMPBY(oparg); + } + else if (err == 0) + ; + else + goto error; + } + DISPATCH(); + } + + TARGET(POP_JUMP_BACKWARD_IF_NOT_NONE) { PyObject *value = POP(); if (!Py_IsNone(value)) { Py_DECREF(value); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3981,11 +4046,20 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_IF_NONE) { + TARGET(POP_JUMP_FORWARD_IF_NOT_NONE) { + PyObject *value = POP(); + if (!Py_IsNone(value)) { + JUMPBY(oparg); + } + Py_DECREF(value); + DISPATCH(); + } + + TARGET(POP_JUMP_BACKWARD_IF_NONE) { PyObject *value = POP(); if (Py_IsNone(value)) { Py_DECREF(value); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3993,6 +4067,15 @@ handle_eval_breaker: DISPATCH(); } + TARGET(POP_JUMP_FORWARD_IF_NONE) { + PyObject *value = POP(); + if (Py_IsNone(value)) { + JUMPBY(oparg); + } + Py_DECREF(value); + DISPATCH(); + } + TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = TOP(); int err; @@ -4108,7 +4191,8 @@ handle_eval_breaker: PyObject *res = match ? Py_True : Py_False; Py_INCREF(res); PUSH(res); - PREDICT(POP_JUMP_IF_FALSE); + PREDICT(POP_JUMP_FORWARD_IF_FALSE); + PREDICT(POP_JUMP_BACKWARD_IF_FALSE); DISPATCH(); } @@ -4118,7 +4202,8 @@ handle_eval_breaker: PyObject *res = match ? Py_True : Py_False; Py_INCREF(res); PUSH(res); - PREDICT(POP_JUMP_IF_FALSE); + PREDICT(POP_JUMP_FORWARD_IF_FALSE); + PREDICT(POP_JUMP_BACKWARD_IF_FALSE); DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index f04ba9ec50f..38cf5f36270 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -78,8 +78,12 @@ #define POP_BLOCK -4 #define JUMP -5 #define JUMP_NO_INTERRUPT -6 +#define POP_JUMP_IF_FALSE -7 +#define POP_JUMP_IF_TRUE -8 +#define POP_JUMP_IF_NONE -9 +#define POP_JUMP_IF_NOT_NONE -10 -#define MIN_VIRTUAL_OPCODE -6 +#define MIN_VIRTUAL_OPCODE -10 #define MAX_ALLOWED_OPCODE 254 #define IS_WITHIN_OPCODE_RANGE(opcode) \ @@ -87,11 +91,36 @@ #define IS_VIRTUAL_OPCODE(opcode) ((opcode) < 0) +#define IS_VIRTUAL_JUMP_OPCODE(opcode) \ + ((opcode) == JUMP || \ + (opcode) == JUMP_NO_INTERRUPT || \ + (opcode) == POP_JUMP_IF_NONE || \ + (opcode) == POP_JUMP_IF_NOT_NONE || \ + (opcode) == POP_JUMP_IF_FALSE || \ + (opcode) == POP_JUMP_IF_TRUE) + /* opcodes which are not emitted in codegen stage, only by the assembler */ #define IS_ASSEMBLER_OPCODE(opcode) \ ((opcode) == JUMP_FORWARD || \ (opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + (opcode) == JUMP_BACKWARD_NO_INTERRUPT || \ + (opcode) == POP_JUMP_FORWARD_IF_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_NONE || \ + (opcode) == POP_JUMP_FORWARD_IF_NOT_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_NOT_NONE || \ + (opcode) == POP_JUMP_FORWARD_IF_TRUE || \ + (opcode) == POP_JUMP_BACKWARD_IF_TRUE || \ + (opcode) == POP_JUMP_FORWARD_IF_FALSE || \ + (opcode) == POP_JUMP_BACKWARD_IF_FALSE) + + +#define IS_BACKWARDS_JUMP_OPCODE(opcode) \ + ((opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT || \ + (opcode) == POP_JUMP_BACKWARD_IF_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_NOT_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_TRUE || \ + (opcode) == POP_JUMP_BACKWARD_IF_FALSE) #define IS_TOP_LEVEL_AWAIT(c) ( \ @@ -156,7 +185,7 @@ is_block_push(struct instr *instr) static inline int is_jump(struct instr *i) { - return i->i_opcode == JUMP || + return IS_VIRTUAL_JUMP_OPCODE(i->i_opcode) || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); } @@ -1027,10 +1056,18 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_IF_FALSE_OR_POP: return jump ? 0 : -1; - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: + case POP_JUMP_BACKWARD_IF_NONE: + case POP_JUMP_FORWARD_IF_NONE: case POP_JUMP_IF_NONE: + case POP_JUMP_BACKWARD_IF_NOT_NONE: + case POP_JUMP_FORWARD_IF_NOT_NONE: case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_FORWARD_IF_FALSE: + case POP_JUMP_BACKWARD_IF_FALSE: + case POP_JUMP_IF_FALSE: + case POP_JUMP_FORWARD_IF_TRUE: + case POP_JUMP_BACKWARD_IF_TRUE: + case POP_JUMP_IF_TRUE: return -1; case LOAD_GLOBAL: @@ -7609,14 +7646,33 @@ normalize_jumps(struct assembler *a) } struct instr *last = &b->b_instr[b->b_iused-1]; assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - if (last->i_opcode == JUMP) { + if (is_jump(last)) { bool is_forward = last->i_target->b_visited == 0; - last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; - } - if (last->i_opcode == JUMP_NO_INTERRUPT) { - bool is_forward = last->i_target->b_visited == 0; - last->i_opcode = is_forward ? - JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + switch(last->i_opcode) { + case JUMP: + last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + break; + case JUMP_NO_INTERRUPT: + last->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + break; + case POP_JUMP_IF_NOT_NONE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_NOT_NONE : POP_JUMP_BACKWARD_IF_NOT_NONE; + break; + case POP_JUMP_IF_NONE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_NONE : POP_JUMP_BACKWARD_IF_NONE; + break; + case POP_JUMP_IF_FALSE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_FALSE : POP_JUMP_BACKWARD_IF_FALSE; + break; + case POP_JUMP_IF_TRUE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_TRUE : POP_JUMP_BACKWARD_IF_TRUE; + break; + } } } } @@ -7652,16 +7708,17 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) instr->i_oparg = instr->i_target->b_offset; if (is_relative_jump(instr)) { if (instr->i_oparg < bsize) { - assert(instr->i_opcode == JUMP_BACKWARD || - instr->i_opcode == JUMP_BACKWARD_NO_INTERRUPT); + assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg = bsize - instr->i_oparg; } else { - assert(instr->i_opcode != JUMP_BACKWARD); - assert(instr->i_opcode != JUMP_BACKWARD_NO_INTERRUPT); + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg -= bsize; } } + else { + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + } if (instr_size(instr) != isize) { extended_arg_recompile = 1; } @@ -8644,7 +8701,7 @@ apply_static_swaps(basicblock *block, int i) static bool jump_thread(struct instr *inst, struct instr *target, int opcode) { - assert(!IS_VIRTUAL_OPCODE(opcode) || opcode == JUMP); + assert(!IS_VIRTUAL_OPCODE(opcode) || IS_VIRTUAL_JUMP_OPCODE(opcode)); assert(is_jump(inst)); assert(is_jump(target)); // bpo-45773: If inst->i_target == target->i_target, then nothing actually diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 064aa060c84..5268c4f2a27 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -113,8 +113,8 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, &&TARGET_PRECALL_NO_KW_STR_1, - &&TARGET_POP_JUMP_IF_FALSE, - &&TARGET_POP_JUMP_IF_TRUE, + &&TARGET_POP_JUMP_FORWARD_IF_FALSE, + &&TARGET_POP_JUMP_FORWARD_IF_TRUE, &&TARGET_LOAD_GLOBAL, &&TARGET_IS_OP, &&TARGET_CONTAINS_OP, @@ -127,8 +127,8 @@ static void *opcode_targets[256] = { &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, &&TARGET_PRECALL_NO_KW_TYPE_1, - &&TARGET_POP_JUMP_IF_NOT_NONE, - &&TARGET_POP_JUMP_IF_NONE, + &&TARGET_POP_JUMP_FORWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_FORWARD_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, @@ -172,6 +172,10 @@ static void *opcode_targets[256] = { &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, &&TARGET_CALL, &&TARGET_KW_NAMES, + &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_BACKWARD_IF_NONE, + &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, + &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, @@ -250,9 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; diff --git a/Python/specialize.c b/Python/specialize.c index 36b05026489..3a8b768549c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1883,7 +1883,10 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); int next_opcode = _Py_OPCODE(instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1]); - if (next_opcode != POP_JUMP_IF_FALSE && next_opcode != POP_JUMP_IF_TRUE) { + if (next_opcode != POP_JUMP_FORWARD_IF_FALSE && + next_opcode != POP_JUMP_BACKWARD_IF_FALSE && + next_opcode != POP_JUMP_FORWARD_IF_TRUE && + next_opcode != POP_JUMP_BACKWARD_IF_TRUE) { // Can't ever combine, so don't don't bother being adaptive (unless // we're collecting stats, where it's more important to get accurate hit // counts for the unadaptive version and each of the different failure @@ -1901,9 +1904,14 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, } assert(oparg <= Py_GE); int when_to_jump_mask = compare_masks[oparg]; - if (next_opcode == POP_JUMP_IF_FALSE) { + if (next_opcode == POP_JUMP_FORWARD_IF_FALSE || + next_opcode == POP_JUMP_BACKWARD_IF_FALSE) { when_to_jump_mask = (1 | 2 | 4) & ~when_to_jump_mask; } + if (next_opcode == POP_JUMP_BACKWARD_IF_TRUE || + next_opcode == POP_JUMP_BACKWARD_IF_FALSE) { + when_to_jump_mask <<= 3; + } if (Py_TYPE(lhs) != Py_TYPE(rhs)) { SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); goto failure; @@ -1931,7 +1939,7 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, } else { _Py_SET_OPCODE(*instr, COMPARE_OP_STR_JUMP); - cache->mask = (when_to_jump_mask & 2) == 0; + cache->mask = when_to_jump_mask; goto success; } }