From 4c72517cada147b215cf30ff8dac70ea0f08f1e0 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 1 Sep 2022 21:36:47 +0100 Subject: gh-93554: Conditional jump opcodes only jump forward (GH-96318) --- Doc/library/dis.rst | 56 ++---- Include/internal/pycore_opcode.h | 46 +++-- Include/opcode.h | 40 ++-- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 19 +- Lib/test/test_dis.py | 206 ++++++++++----------- Lib/test/test_peepholer.py | 9 +- .../2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst | 16 ++ Objects/frameobject.c | 19 +- Python/ceval.c | 147 ++------------- Python/compile.c | 154 ++++++++------- Python/opcode_targets.h | 16 +- Python/specialize.c | 15 +- 13 files changed, 298 insertions(+), 448 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 691819f..47e4bf6 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -999,60 +999,48 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: POP_JUMP_FORWARD_IF_TRUE (delta) +.. opcode:: POP_JUMP_IF_TRUE (delta) If TOS is true, increments the bytecode counter by *delta*. TOS is popped. - .. versionadded:: 3.11 - - -.. opcode:: POP_JUMP_BACKWARD_IF_TRUE (delta) - - If TOS is true, decrements the bytecode counter by *delta*. TOS is popped. - - .. versionadded:: 3.11 + .. versionchanged:: 3.11 + The oparg is now a relative delta rather than an absolute target. + This opcode is a pseudo-instruction, replaced in final bytecode by + the directed versions (forward/backward). + .. versionchanged:: 3.12 + This is no longer a pseudo-instruction. -.. opcode:: POP_JUMP_FORWARD_IF_FALSE (delta) +.. opcode:: POP_JUMP_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 + .. versionchanged:: 3.11 + The oparg is now a relative delta rather than an absolute target. + This opcode is a pseudo-instruction, replaced in final bytecode by + the directed versions (forward/backward). + .. versionchanged:: 3.12 + This is no longer a pseudo-instruction. -.. opcode:: POP_JUMP_FORWARD_IF_NOT_NONE (delta) +.. opcode:: POP_JUMP_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 + .. versionchanged:: 3.12 + This is no longer a pseudo-instruction. -.. opcode:: POP_JUMP_FORWARD_IF_NONE (delta) +.. opcode:: POP_JUMP_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 + .. versionchanged:: 3.12 + This is no longer a pseudo-instruction. .. opcode:: JUMP_IF_TRUE_OR_POP (delta) @@ -1433,10 +1421,6 @@ but are replaced by real opcodes or removed before bytecode is generated. .. opcode:: JUMP .. opcode:: JUMP_NO_INTERRUPT -.. opcode:: POP_JUMP_IF_FALSE -.. opcode:: POP_JUMP_IF_TRUE -.. opcode:: POP_JUMP_IF_NONE -.. opcode:: POP_JUMP_IF_NOT_NONE Undirected relative jump instructions which are replaced by their directed (forward/backward) counterparts by the assembler. diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 5875901..1592551 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -23,10 +23,10 @@ static const uint32_t _PyOpcode_RelativeJump[9] = { 536870912U, 135118848U, 4163U, - 122880U, 0U, 0U, - 1008U, + 0U, + 48U, }; static const uint32_t _PyOpcode_Jump[9] = { 0U, @@ -34,10 +34,10 @@ static const uint32_t _PyOpcode_Jump[9] = { 536870912U, 135118848U, 4163U, - 122880U, 0U, 0U, - 1008U, + 0U, + 48U, }; const uint8_t _PyOpcode_Caches[256] = { @@ -187,14 +187,10 @@ const uint8_t _PyOpcode_Deopt[256] = { [MATCH_SEQUENCE] = MATCH_SEQUENCE, [NOP] = NOP, [POP_EXCEPT] = POP_EXCEPT, - [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_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_TOP] = POP_TOP, [PREP_RERAISE_STAR] = PREP_RERAISE_STAR, [PRINT_EXPR] = PRINT_EXPR, @@ -243,7 +239,7 @@ const uint8_t _PyOpcode_Deopt[256] = { #endif // NEED_OPCODE_TABLES #ifdef Py_DEBUG -static const char *const _PyOpcode_OpName[267] = { +static const char *const _PyOpcode_OpName[263] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", [PUSH_NULL] = "PUSH_NULL", @@ -358,8 +354,8 @@ static const char *const _PyOpcode_OpName[267] = { [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", - [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", + [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", + [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", [IS_OP] = "IS_OP", [CONTAINS_OP] = "CONTAINS_OP", @@ -372,8 +368,8 @@ static const char *const _PyOpcode_OpName[267] = { [STORE_FAST] = "STORE_FAST", [DELETE_FAST] = "DELETE_FAST", [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK", - [POP_JUMP_FORWARD_IF_NOT_NONE] = "POP_JUMP_FORWARD_IF_NOT_NONE", - [POP_JUMP_FORWARD_IF_NONE] = "POP_JUMP_FORWARD_IF_NONE", + [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", + [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", [MAKE_FUNCTION] = "MAKE_FUNCTION", @@ -417,10 +413,6 @@ static const char *const _PyOpcode_OpName[267] = { [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", - [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", - [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", - [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", - [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", @@ -429,6 +421,10 @@ static const char *const _PyOpcode_OpName[267] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [181] = "<181>", + [182] = "<182>", + [183] = "<183>", + [184] = "<184>", [185] = "<185>", [186] = "<186>", [187] = "<187>", @@ -506,15 +502,15 @@ static const char *const _PyOpcode_OpName[267] = { [POP_BLOCK] = "POP_BLOCK", [JUMP] = "JUMP", [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT", - [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", - [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", - [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", - [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", [LOAD_METHOD] = "LOAD_METHOD", }; #endif #define EXTRA_CASES \ + case 181: \ + case 182: \ + case 183: \ + case 184: \ case 185: \ case 186: \ case 187: \ diff --git a/Include/opcode.h b/Include/opcode.h index cf11e55..42825df 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -72,8 +72,8 @@ extern "C" { #define JUMP_FORWARD 110 #define JUMP_IF_FALSE_OR_POP 111 #define JUMP_IF_TRUE_OR_POP 112 -#define POP_JUMP_FORWARD_IF_FALSE 114 -#define POP_JUMP_FORWARD_IF_TRUE 115 +#define POP_JUMP_IF_FALSE 114 +#define POP_JUMP_IF_TRUE 115 #define LOAD_GLOBAL 116 #define IS_OP 117 #define CONTAINS_OP 118 @@ -85,8 +85,8 @@ extern "C" { #define STORE_FAST 125 #define DELETE_FAST 126 #define LOAD_FAST_CHECK 127 -#define POP_JUMP_FORWARD_IF_NOT_NONE 128 -#define POP_JUMP_FORWARD_IF_NONE 129 +#define POP_JUMP_IF_NOT_NONE 128 +#define POP_JUMP_IF_NONE 129 #define RAISE_VARARGS 130 #define GET_AWAITABLE 131 #define MAKE_FUNCTION 132 @@ -117,10 +117,6 @@ extern "C" { #define DICT_UPDATE 165 #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 MIN_PSEUDO_OPCODE 256 #define SETUP_FINALLY 256 #define SETUP_CLEANUP 257 @@ -128,12 +124,8 @@ extern "C" { #define POP_BLOCK 259 #define JUMP 260 #define JUMP_NO_INTERRUPT 261 -#define POP_JUMP_IF_FALSE 262 -#define POP_JUMP_IF_TRUE 263 -#define POP_JUMP_IF_NONE 264 -#define POP_JUMP_IF_NOT_NONE 265 -#define LOAD_METHOD 266 -#define MAX_PSEUDO_OPCODE 266 +#define LOAD_METHOD 262 +#define MAX_PSEUDO_OPCODE 262 #define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADD_FLOAT 4 #define BINARY_OP_ADD_INT 5 @@ -199,23 +191,19 @@ extern "C" { #define STORE_ATTR_SLOT 168 #define STORE_ATTR_WITH_HINT 169 #define STORE_FAST__LOAD_FAST 170 -#define STORE_FAST__STORE_FAST 177 -#define STORE_SUBSCR_ADAPTIVE 178 -#define STORE_SUBSCR_DICT 179 -#define STORE_SUBSCR_LIST_INT 180 -#define UNPACK_SEQUENCE_ADAPTIVE 181 -#define UNPACK_SEQUENCE_LIST 182 -#define UNPACK_SEQUENCE_TUPLE 183 -#define UNPACK_SEQUENCE_TWO_TUPLE 184 +#define STORE_FAST__STORE_FAST 173 +#define STORE_SUBSCR_ADAPTIVE 174 +#define STORE_SUBSCR_DICT 175 +#define STORE_SUBSCR_LIST_INT 176 +#define UNPACK_SEQUENCE_ADAPTIVE 177 +#define UNPACK_SEQUENCE_LIST 178 +#define UNPACK_SEQUENCE_TUPLE 179 +#define UNPACK_SEQUENCE_TWO_TUPLE 180 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ || ((op) == JUMP_NO_INTERRUPT) \ - || ((op) == POP_JUMP_IF_FALSE) \ - || ((op) == POP_JUMP_IF_TRUE) \ - || ((op) == POP_JUMP_IF_NONE) \ - || ((op) == POP_JUMP_IF_NOT_NONE) \ || ((op) == LOAD_METHOD) \ ) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index b30d089..b3c31b9 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -412,6 +412,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.12a1 3506 (Add BINARY_SLICE and STORE_SLICE instructions) # Python 3.12a1 3507 (Set lineno of module's RESUME to 0) # Python 3.12a1 3508 (Add CLEANUP_THROW) +# Python 3.12a1 3509 (Conditional jumps only jump forward) # Python 3.13 will start with 3550 @@ -424,7 +425,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 = (3508).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3509).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 52c1271..6909230 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -153,8 +153,8 @@ name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of words to skip 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) +jrel_op('POP_JUMP_IF_FALSE', 114) +jrel_op('POP_JUMP_IF_TRUE', 115) name_op('LOAD_GLOBAL', 116) # Index in name list def_op('IS_OP', 117) def_op('CONTAINS_OP', 118) @@ -170,8 +170,8 @@ def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) def_op('LOAD_FAST_CHECK', 127) # Local variable number haslocal.append(127) -jrel_op('POP_JUMP_FORWARD_IF_NOT_NONE', 128) -jrel_op('POP_JUMP_FORWARD_IF_NONE', 129) +jrel_op('POP_JUMP_IF_NOT_NONE', 128) +jrel_op('POP_JUMP_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 @@ -216,10 +216,6 @@ def_op('CALL', 171) 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) hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT]) @@ -235,11 +231,8 @@ pseudo_op('POP_BLOCK', 259, ['NOP']) pseudo_op('JUMP', 260, ['JUMP_FORWARD', 'JUMP_BACKWARD']) pseudo_op('JUMP_NO_INTERRUPT', 261, ['JUMP_FORWARD', 'JUMP_BACKWARD_NO_INTERRUPT']) -pseudo_op('POP_JUMP_IF_FALSE', 262, ['POP_JUMP_FORWARD_IF_FALSE', 'POP_JUMP_BACKWARD_IF_FALSE']) -pseudo_op('POP_JUMP_IF_TRUE', 263, ['POP_JUMP_FORWARD_IF_TRUE', 'POP_JUMP_BACKWARD_IF_TRUE']) -pseudo_op('POP_JUMP_IF_NONE', 264, ['POP_JUMP_FORWARD_IF_NONE', 'POP_JUMP_BACKWARD_IF_NONE']) -pseudo_op('POP_JUMP_IF_NOT_NONE', 265, ['POP_JUMP_FORWARD_IF_NOT_NONE', 'POP_JUMP_BACKWARD_IF_NOT_NONE']) -pseudo_op('LOAD_METHOD', 266, ['LOAD_ATTR']) + +pseudo_op('LOAD_METHOD', 262, ['LOAD_ATTR']) MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1 diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 67cb150..48d5960 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -366,7 +366,7 @@ dis_traceback = """\ %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_FALSE 22 (to 80) + POP_JUMP_IF_FALSE 22 (to 80) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -447,7 +447,7 @@ dis_with = """\ %3d >> PUSH_EXC_INFO WITH_EXCEPT_START - POP_JUMP_FORWARD_IF_TRUE 1 (to 46) + POP_JUMP_IF_TRUE 1 (to 46) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -520,7 +520,7 @@ dis_asyncwith = """\ RESUME 3 JUMP_BACKWARD_NO_INTERRUPT 4 (to 82) >> CLEANUP_THROW - >> POP_JUMP_FORWARD_IF_TRUE 1 (to 96) + >> POP_JUMP_IF_TRUE 1 (to 96) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -874,15 +874,7 @@ class DisTests(DisTestBase): self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) def test_widths(self): - long_opcodes = set(['POP_JUMP_FORWARD_IF_FALSE', - 'POP_JUMP_FORWARD_IF_TRUE', - 'POP_JUMP_FORWARD_IF_NOT_NONE', - 'POP_JUMP_FORWARD_IF_NONE', - 'POP_JUMP_BACKWARD_IF_FALSE', - 'POP_JUMP_BACKWARD_IF_TRUE', - 'POP_JUMP_BACKWARD_IF_NOT_NONE', - 'POP_JUMP_BACKWARD_IF_NONE', - 'JUMP_BACKWARD_NO_INTERRUPT', + long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', ]) for opcode, opname in enumerate(dis.opname): if opname in long_opcodes: @@ -1544,7 +1536,7 @@ expected_opinfo_jumpy = [ Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_ITER', opcode=93, arg=29, argval=90, argrepr='to 90', offset=28, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='FOR_ITER', opcode=93, arg=30, argval=92, argrepr='to 92', offset=28, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=32, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=34, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=46, starts_line=None, is_jump_target=False, positions=None), @@ -1553,103 +1545,105 @@ expected_opinfo_jumpy = [ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=60, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=62, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=74, argrepr='to 74', offset=70, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=74, argrepr='to 74', offset=70, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=23, argval=28, argrepr='to 28', offset=72, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=78, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_BACKWARD_IF_FALSE', opcode=175, arg=29, argval=28, argrepr='to 28', offset=84, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=86, starts_line=8, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=116, argrepr='to 116', offset=88, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=90, starts_line=10, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=104, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=114, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=116, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=34, argval=188, argrepr='to 188', offset=118, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=120, starts_line=12, is_jump_target=True, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=132, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=146, starts_line=13, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=148, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=154, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=156, starts_line=14, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=158, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=170, argrepr='to 170', offset=166, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=116, argrepr='to 116', offset=168, starts_line=15, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=170, starts_line=16, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=172, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=174, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=184, argrepr='to 184', offset=180, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=214, argrepr='to 214', offset=182, starts_line=17, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=184, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_BACKWARD_IF_TRUE', opcode=176, arg=34, argval=120, argrepr='to 120', offset=186, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=188, 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=200, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=214, starts_line=20, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=216, starts_line=21, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=218, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=220, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=226, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=230, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=232, starts_line=26, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=244, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=246, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=258, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=260, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=262, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=264, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=276, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=288, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=290, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=302, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', 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=25, 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_FORWARD_IF_TRUE', opcode=115, arg=1, argval=314, argrepr='to 314', 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=276, argrepr='to 276', offset=322, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), - 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_FORWARD_IF_FALSE', opcode=114, arg=16, argval=380, argrepr='to 380', 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), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=374, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=376, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=276, argrepr='to 276', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=380, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=384, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=390, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=402, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=404, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=88, argrepr='to 88', offset=84, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=30, argval=28, argrepr='to 28', offset=86, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=88, starts_line=8, is_jump_target=True, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=118, argrepr='to 118', offset=90, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=92, starts_line=10, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=104, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=106, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=118, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=35, argval=192, argrepr='to 192', offset=120, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=122, starts_line=12, is_jump_target=True, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=134, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=13, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=150, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=152, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=156, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=158, starts_line=14, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=160, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=162, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=118, argrepr='to 118', offset=170, starts_line=15, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=16, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=174, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=176, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_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_FORWARD', opcode=110, arg=16, argval=218, argrepr='to 218', offset=184, starts_line=17, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=192, argrepr='to 192', offset=188, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=35, argval=122, argrepr='to 122', offset=190, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=192, 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=204, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=218, starts_line=20, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=220, starts_line=21, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=222, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=224, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=230, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=234, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=236, starts_line=26, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=248, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=262, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=264, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=266, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=280, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=292, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=306, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=310, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=318, argrepr='to 318', offset=314, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=280, argrepr='to 280', offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=332, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=336, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=384, argrepr='to 384', offset=350, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=354, 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=366, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=280, argrepr='to 280', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=394, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=406, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=408, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 7cd9b06..5f7e50d 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -77,9 +77,8 @@ class TestTranforms(BytecodeTestCase): if not x == 2: del x self.assertNotInBytecode(unot, 'UNARY_NOT') - 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.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE') + self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE') self.check_lnotab(unot) def test_elim_inversion_of_is_or_in(self): @@ -409,7 +408,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_FORWARD_IF_FALSE') + self.assertInBytecode(f, 'POP_JUMP_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) @@ -418,7 +417,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_FORWARD_IF_TRUE') + self.assertInBytecode(f, 'POP_JUMP_IF_TRUE') def test_elim_jump_to_uncond_jump4(self): def f(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst new file mode 100644 index 0000000..dff12ae --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst @@ -0,0 +1,16 @@ +Change the jump opcodes so that all conditional jumps are forward jumps. +Backward jumps are converted by the assembler into a conditional forward +jump whose target is the fallthrough block (and with a reversed condition), +followed by an unconditional backward jump. For example: + +``POP_JUMP_IF_TRUE BACKWARD_TARGET`` becomes ``POP_JUMP_IF_FALSE NEXT_BLOCK; +JUMP BACKWARD_TARGET``. + +All the directed conditional jump opcodes were removed: +``POP_JUMP_FORWARD_IF_TRUE``, ``POP_JUMP_BACKWARD_IF_TRUE``, +``POP_JUMP_FORWARD_IF_FALSE``, ``POP_JUMP_BACKWARD_IF_FALSE``, +``POP_JUMP_FORWARD_IF_NONE``, ``POP_JUMP_BACKWARD_IF_NONE``, +``POP_JUMP_FORWARD_IF_NOT_NONE``, ``POP_JUMP_BACKWARD_IF_NOT_NONE``. + +The corresponding opcodes without direction are no longer pseudo-instructions, +and they implement the forward conditional jumps. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d2647bd..2e37779 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -311,25 +311,12 @@ mark_stacks(PyCodeObject *code_obj, int len) switch (opcode) { case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - case POP_JUMP_FORWARD_IF_FALSE: - case POP_JUMP_BACKWARD_IF_FALSE: - case POP_JUMP_FORWARD_IF_TRUE: - case POP_JUMP_BACKWARD_IF_TRUE: + case POP_JUMP_IF_FALSE: + case POP_JUMP_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 || - opcode == JUMP_IF_FALSE_OR_POP || - opcode == JUMP_IF_TRUE_OR_POP) - { - j += i + 1; - } - else { - assert(opcode == POP_JUMP_BACKWARD_IF_FALSE || - opcode == POP_JUMP_BACKWARD_IF_TRUE); - j = i + 1 - j; - } + j += i + 1; assert(j < len); if (stacks[j] == UNINITIALIZED && j < i) { todo = 1; diff --git a/Python/ceval.c b/Python/ceval.c index c61ccd7..76a8118 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3307,7 +3307,7 @@ handle_eval_breaker: TARGET(COMPARE_OP_FLOAT_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (float ? float) + POP_JUMP_(direction)_IF_(true/false) + // Combined: COMPARE_OP (float ? float) + POP_JUMP_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; int when_to_jump_mask = cache->mask; PyObject *right = TOP(); @@ -3325,23 +3325,12 @@ handle_eval_breaker: STACK_SHRINK(2); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - 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; + assert(opcode == POP_JUMP_IF_FALSE || opcode == POP_JUMP_IF_TRUE); + int jump = (1 << (sign + 1)) & when_to_jump_mask; if (!jump) { next_instr++; } - else if (jump >= 8) { - assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || - opcode == POP_JUMP_BACKWARD_IF_FALSE); - JUMPBY(1 - oparg); - CHECK_EVAL_BREAKER(); - } else { - assert(opcode == POP_JUMP_FORWARD_IF_TRUE || - opcode == POP_JUMP_FORWARD_IF_FALSE); JUMPBY(1 + oparg); } NOTRACE_DISPATCH(); @@ -3349,7 +3338,7 @@ handle_eval_breaker: TARGET(COMPARE_OP_INT_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (int ? int) + POP_JUMP_(direction)_IF_(true/false) + // Combined: COMPARE_OP (int ? int) + POP_JUMP_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; int when_to_jump_mask = cache->mask; PyObject *right = TOP(); @@ -3368,23 +3357,12 @@ handle_eval_breaker: STACK_SHRINK(2); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - 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; + assert(opcode == POP_JUMP_IF_FALSE || opcode == POP_JUMP_IF_TRUE); + int jump = (1 << (sign + 1)) & when_to_jump_mask; if (!jump) { next_instr++; } - else if (jump >= 8) { - assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || - opcode == POP_JUMP_BACKWARD_IF_FALSE); - JUMPBY(1 - oparg); - CHECK_EVAL_BREAKER(); - } else { - assert(opcode == POP_JUMP_FORWARD_IF_TRUE || - opcode == POP_JUMP_FORWARD_IF_FALSE); JUMPBY(1 + oparg); } NOTRACE_DISPATCH(); @@ -3392,9 +3370,9 @@ handle_eval_breaker: TARGET(COMPARE_OP_STR_JUMP) { assert(cframe.use_tracing == 0); - // Combined: COMPARE_OP (str == str or str != str) + POP_JUMP_(direction)_IF_(true/false) + // Combined: COMPARE_OP (str == str or str != str) + POP_JUMP_IF_(true/false) _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; - int when_to_jump_mask = cache->mask; + int invert = cache->mask; PyObject *right = TOP(); PyObject *left = SECOND(); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); @@ -3407,28 +3385,17 @@ handle_eval_breaker: assert(oparg == Py_EQ || oparg == Py_NE); JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP); NEXTOPARG(); - 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); + assert(opcode == POP_JUMP_IF_FALSE || opcode == POP_JUMP_IF_TRUE); STACK_SHRINK(2); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(res == 0 || res == 1); - int sign = 1 - res; - int jump = (9 << (sign + 1)) & when_to_jump_mask; + assert(invert == 0 || invert == 1); + int jump = res ^ invert; if (!jump) { next_instr++; } - else if (jump >= 8) { - assert(opcode == POP_JUMP_BACKWARD_IF_TRUE || - opcode == POP_JUMP_BACKWARD_IF_FALSE); - JUMPBY(1 - oparg); - CHECK_EVAL_BREAKER(); - } else { - assert(opcode == POP_JUMP_FORWARD_IF_TRUE || - opcode == POP_JUMP_FORWARD_IF_FALSE); JUMPBY(1 + oparg); } NOTRACE_DISPATCH(); @@ -3575,34 +3542,8 @@ handle_eval_breaker: JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } - TARGET(POP_JUMP_BACKWARD_IF_FALSE) { - PREDICTED(POP_JUMP_BACKWARD_IF_FALSE); - PyObject *cond = POP(); - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - DISPATCH(); - } - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err > 0) - ; - else if (err == 0) { - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - } - else - goto error; - DISPATCH(); - } - - TARGET(POP_JUMP_FORWARD_IF_FALSE) { - PREDICTED(POP_JUMP_FORWARD_IF_FALSE); + TARGET(POP_JUMP_IF_FALSE) { + PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = POP(); if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); @@ -3625,32 +3566,7 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_BACKWARD_IF_TRUE) { - PyObject *cond = POP(); - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - DISPATCH(); - } - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err > 0) { - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - } - else if (err == 0) - ; - else - goto error; - DISPATCH(); - } - - TARGET(POP_JUMP_FORWARD_IF_TRUE) { + TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = POP(); if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); @@ -3673,19 +3589,7 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_BACKWARD_IF_NOT_NONE) { - PyObject *value = POP(); - if (!Py_IsNone(value)) { - Py_DECREF(value); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - _Py_DECREF_NO_DEALLOC(value); - DISPATCH(); - } - - TARGET(POP_JUMP_FORWARD_IF_NOT_NONE) { + TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = POP(); if (!Py_IsNone(value)) { JUMPBY(oparg); @@ -3694,20 +3598,7 @@ handle_eval_breaker: DISPATCH(); } - TARGET(POP_JUMP_BACKWARD_IF_NONE) { - PyObject *value = POP(); - if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - } - else { - Py_DECREF(value); - } - DISPATCH(); - } - - TARGET(POP_JUMP_FORWARD_IF_NONE) { + TARGET(POP_JUMP_IF_NONE) { PyObject *value = POP(); if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); @@ -3834,8 +3725,7 @@ handle_eval_breaker: PyObject *res = match ? Py_True : Py_False; Py_INCREF(res); PUSH(res); - PREDICT(POP_JUMP_FORWARD_IF_FALSE); - PREDICT(POP_JUMP_BACKWARD_IF_FALSE); + PREDICT(POP_JUMP_IF_FALSE); DISPATCH(); } @@ -3845,8 +3735,7 @@ handle_eval_breaker: PyObject *res = match ? Py_True : Py_False; Py_INCREF(res); PUSH(res); - PREDICT(POP_JUMP_FORWARD_IF_FALSE); - PREDICT(POP_JUMP_BACKWARD_IF_FALSE); + PREDICT(POP_JUMP_IF_FALSE); DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index 857fca4..862999d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -96,23 +96,11 @@ #define IS_ASSEMBLER_OPCODE(opcode) \ ((opcode) == JUMP_FORWARD || \ (opcode) == JUMP_BACKWARD || \ - (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) + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) #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) + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) #define IS_UNCONDITIONAL_JUMP_OPCODE(opcode) \ ((opcode) == JUMP || \ @@ -1146,17 +1134,9 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_IF_FALSE_OR_POP: return jump ? 0 : -1; - 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; @@ -7747,63 +7727,91 @@ assemble_emit(struct assembler *a, struct instr *i) return 1; } -static void -normalize_jumps(basicblock *entryblock) +static int +normalize_jumps_in_block(cfg_builder *g, basicblock *b) { + struct instr *last = basicblock_last_instr(b); + if (last == NULL || !is_jump(last)) { + return 0; + } + assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); + bool is_forward = last->i_target->b_visited == 0; + switch(last->i_opcode) { + case JUMP: + last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + return 0; + case JUMP_NO_INTERRUPT: + last->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + return 0; + } + int reversed_opcode = 0; + switch(last->i_opcode) { + case POP_JUMP_IF_NOT_NONE: + reversed_opcode = POP_JUMP_IF_NONE; + break; + case POP_JUMP_IF_NONE: + reversed_opcode = POP_JUMP_IF_NOT_NONE; + break; + case POP_JUMP_IF_FALSE: + reversed_opcode = POP_JUMP_IF_TRUE; + break; + case POP_JUMP_IF_TRUE: + reversed_opcode = POP_JUMP_IF_FALSE; + 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"); + } + return 0; + } + if (is_forward) { + return 0; + } + + /* transform 'conditional jump T' to + * 'reversed_jump b_next' followed by 'jump_backwards T' + */ + + basicblock *target = last->i_target; + basicblock *backwards_jump = cfg_builder_new_block(g); + if (backwards_jump == NULL) { + return -1; + } + basicblock_addop(backwards_jump, JUMP, target->b_label, NO_LOCATION); + backwards_jump->b_instr[0].i_target = target; + last->i_opcode = reversed_opcode; + last->i_target = b->b_next; + + backwards_jump->b_cold = b->b_cold; + backwards_jump->b_next = b->b_next; + b->b_next = backwards_jump; + return 0; +} + +static int +normalize_jumps(cfg_builder *g) { + basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_visited = 0; } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_visited = 1; - struct instr *last = basicblock_last_instr(b); - if (last == NULL) { - continue; - } - assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - if (is_jump(last)) { - bool is_forward = last->i_target->b_visited == 0; - 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; - 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; - } + if (normalize_jumps_in_block(g, b) < 0) { + return -1; } } + return 0; } static void @@ -8638,7 +8646,9 @@ assemble(struct compiler *c, int addNone) } /* Order of basic blocks must have been determined by now */ - normalize_jumps(g->g_entryblock); + if (normalize_jumps(g) < 0) { + goto error; + } if (add_checks_for_loads_of_unknown_variables(g->g_entryblock, c) < 0) { goto error; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 7c782d1..c1ff367 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_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_POP_JUMP_FORWARD_IF_FALSE, - &&TARGET_POP_JUMP_FORWARD_IF_TRUE, + &&TARGET_POP_JUMP_IF_FALSE, + &&TARGET_POP_JUMP_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_LOAD_FAST_CHECK, - &&TARGET_POP_JUMP_FORWARD_IF_NOT_NONE, - &&TARGET_POP_JUMP_FORWARD_IF_NONE, + &&TARGET_POP_JUMP_IF_NOT_NONE, + &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, @@ -172,10 +172,6 @@ static void *opcode_targets[256] = { &&TARGET_STORE_FAST__LOAD_FAST, &&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_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_STORE_SUBSCR_DICT, @@ -254,5 +250,9 @@ 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 8a2f905..e8c3f46 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1999,10 +1999,8 @@ _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_FORWARD_IF_FALSE && - next_opcode != POP_JUMP_BACKWARD_IF_FALSE && - next_opcode != POP_JUMP_FORWARD_IF_TRUE && - next_opcode != POP_JUMP_BACKWARD_IF_TRUE) { + if (next_opcode != POP_JUMP_IF_FALSE && + next_opcode != POP_JUMP_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 @@ -2021,14 +2019,9 @@ _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_FORWARD_IF_FALSE || - next_opcode == POP_JUMP_BACKWARD_IF_FALSE) { + if (next_opcode == POP_JUMP_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; @@ -2056,7 +2049,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; + cache->mask = (when_to_jump_mask & 2) == 0; goto success; } } -- cgit v0.12