From a00518d9ad9a8f408a9699191019d75dd8406c32 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 31 Mar 2022 14:14:15 +0100 Subject: bpo-47120: Replace the JUMP_ABSOLUTE opcode by the relative JUMP_BACKWARD (GH-32115) --- Doc/library/dis.rst | 12 +- Doc/whatsnew/3.11.rst | 1 + Include/opcode.h | 16 +-- Lib/dis.py | 6 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 8 +- Lib/test/test_dis.py | 12 +- Lib/test/test_peepholer.py | 2 +- .../2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst | 2 + Objects/frameobject.c | 7 +- Programs/test_frozenmain.h | 2 +- Python/ceval.c | 23 ++- Python/compile.c | 156 ++++++++++++--------- Python/opcode_targets.h | 6 +- Python/specialize.c | 4 +- 15 files changed, 147 insertions(+), 113 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 877e11b..d1a0cec 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -895,6 +895,13 @@ iterations of the loop. Increments bytecode counter by *delta*. +.. opcode:: JUMP_BACKWARD (delta) + + Decrements bytecode counter by *delta*. + + .. versionadded:: 3.11 + + .. opcode:: POP_JUMP_IF_TRUE (target) If TOS is true, sets the bytecode counter to *target*. TOS is popped. @@ -974,11 +981,6 @@ iterations of the loop. .. versionadded:: 3.1 -.. opcode:: JUMP_ABSOLUTE (target) - - Set bytecode counter to *target*. - - .. opcode:: JUMP_NO_INTERRUPT (target) Set bytecode counter to *target*. Do not check for interrupts. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 129e87e..1bd9587 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -522,6 +522,7 @@ CPython bytecode changes * :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception. +* Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. Deprecated ========== diff --git a/Include/opcode.h b/Include/opcode.h index 0ce7c15..3a7db43 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -67,7 +67,6 @@ extern "C" { #define JUMP_FORWARD 110 #define JUMP_IF_FALSE_OR_POP 111 #define JUMP_IF_TRUE_OR_POP 112 -#define JUMP_ABSOLUTE 113 #define POP_JUMP_IF_FALSE 114 #define POP_JUMP_IF_TRUE 115 #define LOAD_GLOBAL 116 @@ -94,6 +93,7 @@ extern "C" { #define LOAD_DEREF 137 #define STORE_DEREF 138 #define DELETE_DEREF 139 +#define JUMP_BACKWARD 140 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -135,7 +135,7 @@ extern "C" { #define COMPARE_OP_FLOAT_JUMP 27 #define COMPARE_OP_INT_JUMP 28 #define COMPARE_OP_STR_JUMP 29 -#define JUMP_ABSOLUTE_QUICK 34 +#define JUMP_BACKWARD_QUICK 34 #define LOAD_ATTR_ADAPTIVE 36 #define LOAD_ATTR_INSTANCE_VALUE 37 #define LOAD_ATTR_MODULE 38 @@ -168,7 +168,7 @@ extern "C" { #define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 79 #define PRECALL_NO_KW_STR_1 80 #define PRECALL_NO_KW_TUPLE_1 81 -#define PRECALL_NO_KW_TYPE_1 140 +#define PRECALL_NO_KW_TYPE_1 113 #define PRECALL_PYFUNC 141 #define RESUME_QUICK 143 #define STORE_ATTR_ADAPTIVE 150 @@ -196,7 +196,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 536870912U, 134234112U, - 0U, + 4096U, 0U, 0U, 0U, @@ -205,8 +205,8 @@ static const uint32_t _PyOpcode_Jump[8] = { 0U, 0U, 536870912U, - 2316288000U, - 67U, + 2316156928U, + 4163U, 0U, 0U, 0U, @@ -289,8 +289,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [IMPORT_NAME] = IMPORT_NAME, [IMPORT_STAR] = IMPORT_STAR, [IS_OP] = IS_OP, - [JUMP_ABSOLUTE] = JUMP_ABSOLUTE, - [JUMP_ABSOLUTE_QUICK] = JUMP_ABSOLUTE, + [JUMP_BACKWARD] = JUMP_BACKWARD, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, [JUMP_IF_NOT_EG_MATCH] = JUMP_IF_NOT_EG_MATCH, diff --git a/Lib/dis.py b/Lib/dis.py index 3b7747b..d9936ce 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -30,6 +30,7 @@ MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') LOAD_CONST = opmap['LOAD_CONST'] LOAD_GLOBAL = opmap['LOAD_GLOBAL'] BINARY_OP = opmap['BINARY_OP'] +JUMP_BACKWARD = opmap['JUMP_BACKWARD'] CACHE = opmap["CACHE"] @@ -441,7 +442,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None, argval = arg*2 argrepr = "to " + repr(argval) elif op in hasjrel: - argval = offset + 2 + arg*2 + signed_arg = -arg if op == JUMP_BACKWARD else arg + argval = offset + 2 + signed_arg*2 argrepr = "to " + repr(argval) elif op in haslocal or op in hasfree: argval, argrepr = _get_name_info(arg, varname_from_oparg) @@ -566,6 +568,8 @@ def findlabels(code): for offset, op, arg in _unpack_opargs(code): if arg is not None: if op in hasjrel: + if op == JUMP_BACKWARD: + arg = -arg label = offset + 2 + arg*2 elif op in hasjabs: label = arg*2 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 48b55bb..744fefd 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -396,6 +396,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a6 3486 (Use inline caching for PRECALL and CALL) # Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism) # Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL) +# Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE) # Python 3.12 will start with magic number 3500 @@ -410,7 +411,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 = (3488).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3489).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 0b463d3..6bc6417 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -128,10 +128,9 @@ def_op('COMPARE_OP', 107, 2) # Comparison operator hascompare.append(107) name_op('IMPORT_NAME', 108) # Index in name list name_op('IMPORT_FROM', 109) # Index in name list -jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip +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('JUMP_ABSOLUTE', 113) # "" jabs_op('POP_JUMP_IF_FALSE', 114) # "" jabs_op('POP_JUMP_IF_TRUE', 115) # "" name_op('LOAD_GLOBAL', 116, 5) # Index in name list @@ -166,6 +165,7 @@ def_op('STORE_DEREF', 138) hasfree.append(138) def_op('DELETE_DEREF', 139) hasfree.append(139) +jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) def_op('CALL_FUNCTION_EX', 142) # Flags @@ -259,8 +259,8 @@ _specializations = { "COMPARE_OP_INT_JUMP", "COMPARE_OP_STR_JUMP", ], - "JUMP_ABSOLUTE": [ - "JUMP_ABSOLUTE_QUICK", + "JUMP_BACKWARD": [ + "JUMP_BACKWARD_QUICK", ], "LOAD_ATTR": [ "LOAD_ATTR_ADAPTIVE", diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 16bfee1..99db8ba 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -149,7 +149,7 @@ dis_bug708901 = """\ >> FOR_ITER 2 (to 40) STORE_FAST 0 (res) -%3d JUMP_ABSOLUTE 17 (to 34) +%3d JUMP_BACKWARD 3 (to 34) %3d >> LOAD_CONST 0 (None) RETURN_VALUE @@ -354,7 +354,7 @@ dis_compound_stmt_str = """\ BINARY_OP 13 (+=) STORE_NAME 0 (x) - 2 JUMP_ABSOLUTE 4 (to 8) + 2 JUMP_BACKWARD 6 (to 8) """ dis_traceback = """\ @@ -574,7 +574,7 @@ Disassembly of at 0x..., file "%s", line %d>: LOAD_FAST 1 (z) BINARY_OP 0 (+) LIST_APPEND 2 - JUMP_ABSOLUTE 4 (to 8) + JUMP_BACKWARD 8 (to 8) >> RETURN_VALUE """ % (dis_nested_1, __file__, @@ -1227,14 +1227,14 @@ expected_opinfo_jumpy = [ 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='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=78, starts_line=6, 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_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_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, 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), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, 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=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), @@ -1255,7 +1255,7 @@ expected_opinfo_jumpy = [ 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='JUMP_ABSOLUTE', opcode=113, arg=64, argval=128, argrepr='to 128', offset=184, starts_line=15, 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), diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 6f24b29..ab715e2 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -127,7 +127,7 @@ class TestTranforms(BytecodeTestCase): return list for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'): self.assertNotInBytecode(f, elem) - for elem in ('JUMP_ABSOLUTE',): + for elem in ('JUMP_BACKWARD',): self.assertInBytecode(f, elem) self.check_lnotab(f) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst new file mode 100644 index 0000000..65208c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst @@ -0,0 +1,2 @@ +Replaced :opcode:`JUMP_ABSOLUTE` by the relative jump :opcode:`JUMP_BACKWARD`. + diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 13dfbf6..d4993104 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -237,7 +237,6 @@ mark_stacks(PyCodeObject *code_obj, int len) stacks[i+1] = next_stack; break; } - case JUMP_ABSOLUTE: case JUMP_NO_INTERRUPT: j = get_arg(code, i); assert(j < len); @@ -264,6 +263,12 @@ mark_stacks(PyCodeObject *code_obj, int len) assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; + case JUMP_BACKWARD: + j = i + 1 - get_arg(code, i); + assert(j >= 0); + assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); + stacks[j] = next_stack; + break; case GET_ITER: case GET_AITER: next_stack = push_value(pop_value(next_stack), Iterator); diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 8cae77a..a3c0952 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -12,7 +12,7 @@ unsigned char M_test_frozenmain[] = { 68,0,93,25,90,6,2,0,101,2,100,6,101,6,155,0, 100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0, 155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0, - 0,0,1,0,113,60,100,1,83,0,41,8,233,0,0,0, + 0,0,1,0,140,26,100,1,83,0,41,8,233,0,0,0, 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111, 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118, 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103, diff --git a/Python/ceval.c b/Python/ceval.c index a7b3777..8f73ea1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2218,7 +2218,7 @@ handle_eval_breaker: Py_DECREF(v); if (err != 0) goto error; - PREDICT(JUMP_ABSOLUTE); + PREDICT(JUMP_BACKWARD_QUICK); DISPATCH(); } @@ -2230,7 +2230,7 @@ handle_eval_breaker: Py_DECREF(v); if (err != 0) goto error; - PREDICT(JUMP_ABSOLUTE); + PREDICT(JUMP_BACKWARD_QUICK); DISPATCH(); } @@ -3396,7 +3396,7 @@ handle_eval_breaker: if (_PyDict_SetItem_Take2((PyDictObject *)map, key, value) != 0) { goto error; } - PREDICT(JUMP_ABSOLUTE); + PREDICT(JUMP_BACKWARD_QUICK); DISPATCH(); } @@ -3926,6 +3926,11 @@ handle_eval_breaker: DISPATCH(); } + TARGET(JUMP_BACKWARD) { + _PyCode_Warmup(frame->f_code); + JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + } + TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = POP(); @@ -4053,12 +4058,6 @@ handle_eval_breaker: DISPATCH(); } - TARGET(JUMP_ABSOLUTE) { - PREDICTED(JUMP_ABSOLUTE); - _PyCode_Warmup(frame->f_code); - JUMP_TO_INSTRUCTION(JUMP_ABSOLUTE_QUICK); - } - TARGET(JUMP_NO_INTERRUPT) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost @@ -4069,10 +4068,10 @@ handle_eval_breaker: DISPATCH(); } - TARGET(JUMP_ABSOLUTE_QUICK) { - PREDICTED(JUMP_ABSOLUTE_QUICK); + TARGET(JUMP_BACKWARD_QUICK) { + PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index 06edcf1..7a07377 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -76,6 +76,7 @@ #define SETUP_CLEANUP 254 #define SETUP_WITH 253 #define POP_BLOCK 252 +#define JUMP 251 #define IS_TOP_LEVEL_AWAIT(c) ( \ (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ @@ -127,7 +128,9 @@ is_relative_jump(struct instr *i) static inline int is_jump(struct instr *i) { - return i->i_opcode >= SETUP_WITH || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); + return i->i_opcode >= SETUP_WITH || + i->i_opcode == JUMP || + is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); } static int @@ -985,7 +988,8 @@ stack_effect(int opcode, int oparg, int jump) /* Jumps */ case JUMP_FORWARD: - case JUMP_ABSOLUTE: + case JUMP_BACKWARD: + case JUMP: case JUMP_NO_INTERRUPT: return 0; @@ -2839,7 +2843,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) return 0; if (!compiler_jump_if(c, e->v.IfExp.body, next, cond)) return 0; - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); compiler_use_next_block(c, next2); if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond)) return 0; @@ -2870,11 +2874,11 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) basicblock *end = compiler_new_block(c); if (end == NULL) return 0; - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); compiler_use_next_block(c, cleanup); ADDOP(c, POP_TOP); if (!cond) { - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, next); + ADDOP_JUMP_NOLINE(c, JUMP, next); } compiler_use_next_block(c, end); return 1; @@ -2908,7 +2912,7 @@ compiler_ifexp(struct compiler *c, expr_ty e) if (!compiler_jump_if(c, e->v.IfExp.test, next, 0)) return 0; VISIT(c, expr, e->v.IfExp.body); - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); compiler_use_next_block(c, next); VISIT(c, expr, e->v.IfExp.orelse); compiler_use_next_block(c, end); @@ -2995,7 +2999,7 @@ compiler_if(struct compiler *c, stmt_ty s) } VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); compiler_use_next_block(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); } @@ -3027,7 +3031,7 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.For.body); /* Mark jump as artificial */ UNSET_LOC(c); - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + ADDOP_JUMP(c, JUMP, start); compiler_use_next_block(c, cleanup); compiler_pop_fblock(c, FOR_LOOP, start); @@ -3072,7 +3076,7 @@ compiler_async_for(struct compiler *c, stmt_ty s) /* Success block for __anext__ */ VISIT(c, expr, s->v.AsyncFor.target); VISIT_SEQ(c, stmt, s->v.AsyncFor.body); - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + ADDOP_JUMP(c, JUMP, start); compiler_pop_fblock(c, FOR_LOOP, start); @@ -3184,7 +3188,7 @@ compiler_break(struct compiler *c) if (!compiler_unwind_fblock(c, loop, 0)) { return 0; } - ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_exit); + ADDOP_JUMP(c, JUMP, loop->fb_exit); return 1; } @@ -3200,7 +3204,7 @@ compiler_continue(struct compiler *c) if (loop == NULL) { return compiler_error(c, "'continue' not properly in loop"); } - ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_block); + ADDOP_JUMP(c, JUMP, loop->fb_block); return 1; } @@ -3261,7 +3265,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s) ADDOP_NOLINE(c, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.Try.finalbody); - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit); + ADDOP_JUMP_NOLINE(c, JUMP, exit); /* `finally` block */ compiler_use_next_block(c, end); @@ -3315,7 +3319,7 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) ADDOP_NOLINE(c, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit); + ADDOP_JUMP_NOLINE(c, JUMP, exit); /* `finally` block */ compiler_use_next_block(c, end); @@ -3345,13 +3349,13 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) [] SETUP_FINALLY L1 [] [] POP_BLOCK - [] JUMP_FORWARD L0 + [] JUMP L0 [exc] L1: ) [exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1 [exc] (or POP if no V1) [] - JUMP_FORWARD L0 + JUMP L0 [exc] L2: .............................etc....................... @@ -3384,7 +3388,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) { VISIT_SEQ(c, stmt, s->v.Try.orelse); } - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); compiler_use_next_block(c, except); @@ -3447,7 +3451,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP_LOAD_CONST(c, Py_None); compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Del); - ADDOP_JUMP(c, JUMP_FORWARD, end); + ADDOP_JUMP(c, JUMP, end); /* except: */ compiler_use_next_block(c, cleanup_end); @@ -3477,7 +3481,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) UNSET_LOC(c); ADDOP(c, POP_BLOCK); ADDOP(c, POP_EXCEPT); - ADDOP_JUMP(c, JUMP_FORWARD, end); + ADDOP_JUMP(c, JUMP, end); } compiler_use_next_block(c, except); } @@ -3501,7 +3505,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) [] SETUP_FINALLY L1 [] [] POP_BLOCK - [] JUMP_FORWARD L0 + [] JUMP L0 [exc] L1: COPY 1 ) save copy of the original exception [orig, exc] BUILD_LIST ) list for raised/reraised excs ("result") @@ -3514,7 +3518,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) [orig, res, rest] SETUP_FINALLY R1 [orig, res, rest] - [orig, res, rest] JUMP_FORWARD L2 + [orig, res, rest] JUMP L2 [orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res [orig, res, rest, i] POP @@ -3528,7 +3532,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) [exc] COPY 1 [exc, exc] POP_JUMP_IF_NOT_NONE RER [exc] POP_TOP - [] JUMP_FORWARD L0 + [] JUMP L0 [exc] RER: SWAP 2 [exc, prev_exc_info] POP_EXCEPT @@ -3572,7 +3576,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.TryStar.body); compiler_pop_fblock(c, TRY_EXCEPT, body); ADDOP_NOLINE(c, POP_BLOCK); - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, orelse); + ADDOP_JUMP_NOLINE(c, JUMP, orelse); Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers); compiler_use_next_block(c, except); @@ -3657,7 +3661,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Del); } - ADDOP_JUMP(c, JUMP_FORWARD, except); + ADDOP_JUMP(c, JUMP, except); /* except: */ compiler_use_next_block(c, cleanup_end); @@ -3675,13 +3679,13 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP_I(c, LIST_APPEND, 3); // exc ADDOP(c, POP_TOP); // lasti - ADDOP_JUMP(c, JUMP_ABSOLUTE, except); + ADDOP_JUMP(c, JUMP, except); compiler_use_next_block(c, except); if (i == n - 1) { /* Add exc to the list (if not None it's the unhandled part of the EG) */ ADDOP_I(c, LIST_APPEND, 1); - ADDOP_JUMP(c, JUMP_FORWARD, reraise_star); + ADDOP_JUMP(c, JUMP, reraise_star); } } /* Mark as artificial */ @@ -3701,7 +3705,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP(c, POP_TOP); ADDOP(c, POP_BLOCK); ADDOP(c, POP_EXCEPT); - ADDOP_JUMP(c, JUMP_FORWARD, end); + ADDOP_JUMP(c, JUMP, end); compiler_use_next_block(c, reraise); ADDOP(c, POP_BLOCK); ADDOP_I(c, SWAP, 2); @@ -4542,7 +4546,7 @@ compiler_compare(struct compiler *c, expr_ty e) basicblock *end = compiler_new_block(c); if (end == NULL) return 0; - ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); + ADDOP_JUMP_NOLINE(c, JUMP, end); compiler_use_next_block(c, cleanup); ADDOP_I(c, SWAP, 2); ADDOP(c, POP_TOP); @@ -5172,7 +5176,7 @@ compiler_sync_comprehension_generator(struct compiler *c, } compiler_use_next_block(c, if_cleanup); if (start) { - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + ADDOP_JUMP(c, JUMP, start); compiler_use_next_block(c, anchor); } @@ -5266,7 +5270,7 @@ compiler_async_comprehension_generator(struct compiler *c, } } compiler_use_next_block(c, if_cleanup); - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + ADDOP_JUMP(c, JUMP, start); compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start); @@ -5542,7 +5546,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP(c, POP_TOP); - ADDOP_JUMP(c, JUMP_ABSOLUTE, exit); + ADDOP_JUMP(c, JUMP, exit); /* For exceptional outcome: */ compiler_use_next_block(c, final); @@ -5571,7 +5575,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) LOAD_CONST (None, None, None) CALL_FUNCTION_EX 0 - JUMP_FORWARD EXIT + JUMP EXIT E: WITH_EXCEPT_START (calls EXPR.__exit__) POP_JUMP_IF_TRUE T: RERAISE @@ -5638,7 +5642,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) if (!compiler_call_exit_with_nones(c)) return 0; ADDOP(c, POP_TOP); - ADDOP_JUMP(c, JUMP_FORWARD, exit); + ADDOP_JUMP(c, JUMP, exit); /* For exceptional outcome: */ compiler_use_next_block(c, final); @@ -6687,7 +6691,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (!compiler_addop_j(c, JUMP_FORWARD, end) || + if (!compiler_addop_j(c, JUMP, end) || !emit_and_reset_fail_pop(c, pc)) { goto error; @@ -6699,7 +6703,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP_FORWARD)) { + if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP)) { goto error; } compiler_use_next_block(c, end); @@ -6906,7 +6910,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) ADDOP(c, POP_TOP); } VISIT_SEQ(c, stmt, m->body); - ADDOP_JUMP(c, JUMP_FORWARD, end); + ADDOP_JUMP(c, JUMP, end); // If the pattern fails to match, we want the line number of the // cleanup to be associated with the failed pattern, not the last line // of the body @@ -7045,9 +7049,10 @@ stackdepth(struct compiler *c) stackdepth_push(&sp, instr->i_target, target_depth); } depth = new_depth; - if (instr->i_opcode == JUMP_ABSOLUTE || - instr->i_opcode == JUMP_NO_INTERRUPT || - instr->i_opcode == JUMP_FORWARD || + assert(instr->i_opcode != JUMP_FORWARD); + assert(instr->i_opcode != JUMP_BACKWARD); + if (instr->i_opcode == JUMP_NO_INTERRUPT || + instr->i_opcode == JUMP || instr->i_opcode == RETURN_VALUE || instr->i_opcode == RAISE_VARARGS || instr->i_opcode == RERAISE) @@ -7559,14 +7564,14 @@ normalize_jumps(struct assembler *a) continue; } struct instr *last = &b->b_instr[b->b_iused-1]; - if (last->i_opcode == JUMP_ABSOLUTE) { + assert(last->i_opcode != JUMP_FORWARD); + assert(last->i_opcode != JUMP_BACKWARD); + if (last->i_opcode == JUMP) { if (last->i_target->b_visited == 0) { last->i_opcode = JUMP_FORWARD; } - } - if (last->i_opcode == JUMP_FORWARD) { - if (last->i_target->b_visited == 1) { - last->i_opcode = JUMP_ABSOLUTE; + else { + last->i_opcode = JUMP_BACKWARD; } } } @@ -7602,7 +7607,14 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) if (is_jump(instr)) { instr->i_oparg = instr->i_target->b_offset; if (is_relative_jump(instr)) { - instr->i_oparg -= bsize; + if (instr->i_oparg < bsize) { + assert(instr->i_opcode == JUMP_BACKWARD); + instr->i_oparg = bsize - instr->i_oparg; + } + else { + assert(instr->i_opcode != JUMP_BACKWARD); + instr->i_oparg -= bsize; + } } if (instr_size(instr) != isize) { extended_arg_recompile = 1; @@ -8621,10 +8633,14 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) inst->i_target = inst->i_target->b_next; } target = &inst->i_target->b_instr[0]; + assert(target->i_opcode != JUMP_FORWARD); + assert(target->i_opcode != JUMP_BACKWARD); } else { target = &nop; } + assert(inst->i_opcode != JUMP_FORWARD); + assert(inst->i_opcode != JUMP_BACKWARD); switch (inst->i_opcode) { /* Remove LOAD_CONST const; conditional jump */ case LOAD_CONST: @@ -8647,7 +8663,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) inst->i_opcode = NOP; jump_if_true = nextop == POP_JUMP_IF_TRUE; if (is_true == jump_if_true) { - bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE; + bb->b_instr[i+1].i_opcode = JUMP; bb->b_nofallthrough = 1; } else { @@ -8667,7 +8683,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) } jump_if_true = nextop == JUMP_IF_TRUE_OR_POP; if (is_true == jump_if_true) { - bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE; + bb->b_instr[i+1].i_opcode = JUMP; bb->b_nofallthrough = 1; } else { @@ -8738,8 +8754,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) case POP_JUMP_IF_FALSE: i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); break; - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: case JUMP_IF_FALSE_OR_POP: i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP); break; @@ -8761,8 +8776,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) case POP_JUMP_IF_TRUE: i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); break; - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: case JUMP_IF_TRUE_OR_POP: i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP); break; @@ -8782,36 +8796,38 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NONE: switch (target->i_opcode) { - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: i -= jump_thread(inst, target, inst->i_opcode); } break; case POP_JUMP_IF_FALSE: switch (target->i_opcode) { - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); } break; case POP_JUMP_IF_TRUE: switch (target->i_opcode) { - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); } break; - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: switch (target->i_opcode) { - case JUMP_ABSOLUTE: - case JUMP_FORWARD: - i -= jump_thread(inst, target, JUMP_ABSOLUTE); + case JUMP: + i -= jump_thread(inst, target, JUMP); } break; case FOR_ITER: - if (target->i_opcode == JUMP_FORWARD) { + if (target->i_opcode == JUMP) { + /* This will not work now because the jump (at target) could + * be forward or backward and FOR_ITER only jumps forward. We + * can re-enable this if ever we implement a backward version + * of FOR_ITER. + */ + /* i -= jump_thread(inst, target, FOR_ITER); + */ } break; case SWAP: @@ -8852,7 +8868,9 @@ extend_block(basicblock *bb) { return 0; } struct instr *last = &bb->b_instr[bb->b_iused-1]; - if (last->i_opcode != JUMP_ABSOLUTE && last->i_opcode != JUMP_FORWARD) { + if (last->i_opcode != JUMP && + last->i_opcode != JUMP_FORWARD && + last->i_opcode != JUMP_BACKWARD) { return 0; } if (last->i_target->b_exit && last->i_target->b_iused <= MAX_COPY_SIZE) { @@ -8923,6 +8941,8 @@ normalize_basic_block(basicblock *bb) { /* Mark blocks as exit and/or nofallthrough. Raise SystemError if CFG is malformed. */ for (int i = 0; i < bb->b_iused; i++) { + assert(bb->b_instr[i].i_opcode != JUMP_FORWARD); + assert(bb->b_instr[i].i_opcode != JUMP_BACKWARD); switch(bb->b_instr[i].i_opcode) { case RETURN_VALUE: case RAISE_VARARGS: @@ -8930,8 +8950,7 @@ normalize_basic_block(basicblock *bb) { bb->b_exit = 1; bb->b_nofallthrough = 1; break; - case JUMP_ABSOLUTE: - case JUMP_FORWARD: + case JUMP: case JUMP_NO_INTERRUPT: bb->b_nofallthrough = 1; /* fall through */ @@ -9116,9 +9135,10 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts) for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) { if (b->b_iused > 0) { struct instr *b_last_instr = &b->b_instr[b->b_iused - 1]; - if (b_last_instr->i_opcode == JUMP_ABSOLUTE || - b_last_instr->i_opcode == JUMP_NO_INTERRUPT || - b_last_instr->i_opcode == JUMP_FORWARD) { + assert(b_last_instr->i_opcode != JUMP_FORWARD); + assert(b_last_instr->i_opcode != JUMP_BACKWARD); + if (b_last_instr->i_opcode == JUMP || + b_last_instr->i_opcode == JUMP_NO_INTERRUPT) { if (b_last_instr->i_target == b->b_next) { assert(b->b_next->b_iused); b->b_nofallthrough = 0; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index dbcacee..3afaf0b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -33,7 +33,7 @@ static void *opcode_targets[256] = { &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_JUMP_ABSOLUTE_QUICK, + &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_PUSH_EXC_INFO, &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_JUMP_ABSOLUTE, + &&TARGET_PRECALL_NO_KW_TYPE_1, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -139,7 +139,7 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&TARGET_PRECALL_NO_KW_TYPE_1, + &&TARGET_JUMP_BACKWARD, &&TARGET_PRECALL_PYFUNC, &&TARGET_CALL_FUNCTION_EX, &&TARGET_RESUME_QUICK, diff --git a/Python/specialize.c b/Python/specialize.c index 244318a..08c6904 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -270,8 +270,8 @@ _PyCode_Quicken(PyCodeObject *code) else { assert(!_PyOpcode_Caches[opcode]); switch (opcode) { - case JUMP_ABSOLUTE: - _Py_SET_OPCODE(instructions[i], JUMP_ABSOLUTE_QUICK); + case JUMP_BACKWARD: + _Py_SET_OPCODE(instructions[i], JUMP_BACKWARD_QUICK); break; case RESUME: _Py_SET_OPCODE(instructions[i], RESUME_QUICK); -- cgit v0.12