diff options
author | Irit Katriel <1055913+iritkatriel@users.noreply.github.com> | 2022-04-05 11:49:08 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-05 11:49:08 (GMT) |
commit | 0aa8d5cbd89cf3b61d7e8626f3a7b9c4881dfd70 (patch) | |
tree | b28edee28c5dd4cf022135e1204421c9795b3e38 | |
parent | 32091df41ce6e3a71df2cf37dc74b728c0d885f2 (diff) | |
download | cpython-0aa8d5cbd89cf3b61d7e8626f3a7b9c4881dfd70.zip cpython-0aa8d5cbd89cf3b61d7e8626f3a7b9c4881dfd70.tar.gz cpython-0aa8d5cbd89cf3b61d7e8626f3a7b9c4881dfd70.tar.bz2 |
bpo-47120: make JUMP_NO_INTERRUPT relative (GH-32221)
-rw-r--r-- | Doc/library/dis.rst | 16 | ||||
-rw-r--r-- | Doc/whatsnew/3.11.rst | 2 | ||||
-rw-r--r-- | Include/opcode.h | 6 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 3 | ||||
-rw-r--r-- | Lib/opcode.py | 2 | ||||
-rw-r--r-- | Lib/test/test_dis.py | 3 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2022-03-31-21-43-57.bpo-47120.NgxQbA.rst | 1 | ||||
-rw-r--r-- | Objects/frameobject.c | 14 | ||||
-rw-r--r-- | Python/ceval.c | 4 | ||||
-rw-r--r-- | Python/compile.c | 49 | ||||
-rw-r--r-- | Python/opcode_targets.h | 2 |
11 files changed, 56 insertions, 46 deletions
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 63d8467..fa0e23a 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -925,7 +925,14 @@ iterations of the loop. .. opcode:: JUMP_BACKWARD (delta) - Decrements bytecode counter by *delta*. + Decrements bytecode counter by *delta*. Checks for interrupts. + + .. versionadded:: 3.11 + + +.. opcode:: JUMP_BACKWARD_NO_INTERRUPT (delta) + + Decrements bytecode counter by *delta*. Does not check for interrupts. .. versionadded:: 3.11 @@ -974,13 +981,6 @@ iterations of the loop. .. versionadded:: 3.1 -.. opcode:: JUMP_NO_INTERRUPT (target) - - Set bytecode counter to *target*. Do not check for interrupts. - - .. versionadded:: 3.11 - - .. opcode:: FOR_ITER (delta) TOS is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index fae85d8..d0c10a9 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -528,6 +528,8 @@ CPython bytecode changes * Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. +* Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it is undesirable to handle interrupts. + Deprecated ========== diff --git a/Include/opcode.h b/Include/opcode.h index fd49dfe..ff3ffdd 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -87,7 +87,7 @@ extern "C" { #define GET_AWAITABLE 131 #define MAKE_FUNCTION 132 #define BUILD_SLICE 133 -#define JUMP_NO_INTERRUPT 134 +#define JUMP_BACKWARD_NO_INTERRUPT 134 #define MAKE_CELL 135 #define LOAD_CLOSURE 136 #define LOAD_DEREF 137 @@ -196,7 +196,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 536870912U, 134234112U, - 4096U, + 4160U, 0U, 0U, 0U, @@ -292,11 +292,11 @@ const uint8_t _PyOpcode_Deopt[256] = { [IMPORT_STAR] = IMPORT_STAR, [IS_OP] = IS_OP, [JUMP_BACKWARD] = JUMP_BACKWARD, + [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, - [JUMP_NO_INTERRUPT] = JUMP_NO_INTERRUPT, [KW_NAMES] = KW_NAMES, [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 189547c..45be177 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -398,7 +398,8 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL) # Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE) # Python 3.11a6 3490 (remove JUMP_IF_NOT_EXC_MATCH, add CHECK_EXC_MATCH) -# Python 3.11a6 3491 (remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH) +# Python 3.11a6 3491 (remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH, +# add JUMP_BACKWARD_NO_INTERRUPT, make JUMP_NO_INTERRUPT virtual) # Python 3.12 will start with magic number 3500 diff --git a/Lib/opcode.py b/Lib/opcode.py index 23d98df..97b5805 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -154,7 +154,7 @@ def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('GET_AWAITABLE', 131) def_op('MAKE_FUNCTION', 132) # Flags def_op('BUILD_SLICE', 133) # Number of items -jabs_op('JUMP_NO_INTERRUPT', 134) # Target byte offset from beginning of code +jrel_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards) def_op('MAKE_CELL', 135) hasfree.append(135) def_op('LOAD_CLOSURE', 136) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 544e135..2f78d42 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -684,7 +684,8 @@ class DisTests(DisTestBase): def test_widths(self): for opcode, opname in enumerate(dis.opname): if opname in ('BUILD_MAP_UNPACK_WITH_CALL', - 'BUILD_TUPLE_UNPACK_WITH_CALL'): + 'BUILD_TUPLE_UNPACK_WITH_CALL', + 'JUMP_BACKWARD_NO_INTERRUPT'): continue with self.subTest(opname=opname): width = dis._OPNAME_WIDTH diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-31-21-43-57.bpo-47120.NgxQbA.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-21-43-57.bpo-47120.NgxQbA.rst new file mode 100644 index 0000000..236ad94 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-21-43-57.bpo-47120.NgxQbA.rst @@ -0,0 +1 @@ +Replace the absolute jump opcode :opcode:`JUMP_NO_INTERRUPT` by the relative :opcode:`JUMP_BACKWARD_NO_INTERRUPT`. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index c257c0a..6842e62 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -229,15 +229,6 @@ mark_stacks(PyCodeObject *code_obj, int len) stacks[i+1] = next_stack; break; } - case JUMP_NO_INTERRUPT: - j = get_arg(code, i); - assert(j < len); - if (stacks[j] == UNINITIALIZED && j < i) { - todo = 1; - } - assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); - stacks[j] = next_stack; - break; case POP_EXCEPT: next_stack = pop_value(pop_value(pop_value(next_stack))); stacks[i+1] = next_stack; @@ -256,8 +247,13 @@ mark_stacks(PyCodeObject *code_obj, int len) stacks[j] = next_stack; break; case JUMP_BACKWARD: + case JUMP_BACKWARD_NO_INTERRUPT: j = i + 1 - get_arg(code, i); assert(j >= 0); + assert(j < len); + if (stacks[j] == UNINITIALIZED && j < i) { + todo = 1; + } assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; diff --git a/Python/ceval.c b/Python/ceval.c index f7e08c6..9b7c42c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4045,13 +4045,13 @@ handle_eval_breaker: DISPATCH(); } - TARGET(JUMP_NO_INTERRUPT) { + TARGET(JUMP_BACKWARD_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 * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ - JUMPTO(oparg); + JUMPBY(-oparg); DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index c92b267..f04ba9e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -77,8 +77,9 @@ #define SETUP_WITH -3 #define POP_BLOCK -4 #define JUMP -5 +#define JUMP_NO_INTERRUPT -6 -#define MIN_VIRTUAL_OPCODE -5 +#define MIN_VIRTUAL_OPCODE -6 #define MAX_ALLOWED_OPCODE 254 #define IS_WITHIN_OPCODE_RANGE(opcode) \ @@ -86,6 +87,13 @@ #define IS_VIRTUAL_OPCODE(opcode) ((opcode) < 0) +/* opcodes which are not emitted in codegen stage, only by the assembler */ +#define IS_ASSEMBLER_OPCODE(opcode) \ + ((opcode) == JUMP_FORWARD || \ + (opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + + #define IS_TOP_LEVEL_AWAIT(c) ( \ (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && (c->u->u_ste->ste_type == ModuleBlock)) @@ -1011,6 +1019,7 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_FORWARD: case JUMP_BACKWARD: case JUMP: + case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_NO_INTERRUPT: return 0; @@ -1199,6 +1208,7 @@ compiler_addop_line(struct compiler *c, int opcode, int line, int end_line, int col_offset, int end_col_offset) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(!HAS_ARG(opcode) || IS_ARTIFICIAL(opcode)); if (compiler_use_new_implicit_block_if_needed(c) < 0) { @@ -1442,6 +1452,7 @@ compiler_addop_i_line(struct compiler *c, int opcode, Py_ssize_t oparg, EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode)); assert(0 <= oparg && oparg <= 2147483647); @@ -1486,6 +1497,7 @@ static int add_jump_to_block(struct compiler *c, int opcode, basicblock *target) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode) || IS_VIRTUAL_OPCODE(opcode)); assert(target != NULL); @@ -7089,8 +7101,7 @@ stackdepth(struct compiler *c) stackdepth_push(&sp, instr->i_target, target_depth); } depth = new_depth; - assert(instr->i_opcode != JUMP_FORWARD); - assert(instr->i_opcode != JUMP_BACKWARD); + assert(!IS_ASSEMBLER_OPCODE(instr->i_opcode)); if (instr->i_opcode == JUMP_NO_INTERRUPT || instr->i_opcode == JUMP || instr->i_opcode == RETURN_VALUE || @@ -7597,15 +7608,15 @@ normalize_jumps(struct assembler *a) continue; } struct instr *last = &b->b_instr[b->b_iused-1]; - assert(last->i_opcode != JUMP_FORWARD); - assert(last->i_opcode != JUMP_BACKWARD); + assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); if (last->i_opcode == JUMP) { - if (last->i_target->b_visited == 0) { - last->i_opcode = JUMP_FORWARD; - } - else { - last->i_opcode = JUMP_BACKWARD; - } + bool is_forward = last->i_target->b_visited == 0; + last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + } + if (last->i_opcode == JUMP_NO_INTERRUPT) { + bool is_forward = last->i_target->b_visited == 0; + last->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; } } } @@ -7641,11 +7652,13 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) instr->i_oparg = instr->i_target->b_offset; if (is_relative_jump(instr)) { if (instr->i_oparg < bsize) { - assert(instr->i_opcode == JUMP_BACKWARD); + assert(instr->i_opcode == JUMP_BACKWARD || + instr->i_opcode == JUMP_BACKWARD_NO_INTERRUPT); instr->i_oparg = bsize - instr->i_oparg; } else { assert(instr->i_opcode != JUMP_BACKWARD); + assert(instr->i_opcode != JUMP_BACKWARD_NO_INTERRUPT); instr->i_oparg -= bsize; } } @@ -8667,14 +8680,12 @@ 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); + assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); } else { target = &nop; } - assert(inst->i_opcode != JUMP_FORWARD); - assert(inst->i_opcode != JUMP_BACKWARD); + assert(!IS_ASSEMBLER_OPCODE(inst->i_opcode)); switch (inst->i_opcode) { /* Remove LOAD_CONST const; conditional jump */ case LOAD_CONST: @@ -8975,8 +8986,7 @@ 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); + assert(!IS_ASSEMBLER_OPCODE(bb->b_instr[i].i_opcode)); switch(bb->b_instr[i].i_opcode) { case RETURN_VALUE: case RAISE_VARARGS: @@ -9163,8 +9173,7 @@ 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]; - assert(b_last_instr->i_opcode != JUMP_FORWARD); - assert(b_last_instr->i_opcode != JUMP_BACKWARD); + assert(!IS_ASSEMBLER_OPCODE(b_last_instr->i_opcode)); if (b_last_instr->i_opcode == JUMP || b_last_instr->i_opcode == JUMP_NO_INTERRUPT) { if (b_last_instr->i_target == b->b_next) { diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index e71b3e2..064aa06 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -133,7 +133,7 @@ static void *opcode_targets[256] = { &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, - &&TARGET_JUMP_NO_INTERRUPT, + &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, |