diff --git a/Include/opcode.h b/Include/opcode.h index ff3ffddda2147f..7a9382635a2c3b 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -81,8 +81,8 @@ extern "C" { #define LOAD_FAST 124 #define STORE_FAST 125 #define DELETE_FAST 126 -#define POP_JUMP_IF_NOT_NONE 128 -#define POP_JUMP_IF_NONE 129 +#define POP_JUMP_FORWARD_IF_NOT_NONE 128 +#define POP_JUMP_FORWARD_IF_NONE 129 #define RAISE_VARARGS 130 #define GET_AWAITABLE 131 #define MAKE_FUNCTION 132 @@ -114,6 +114,8 @@ extern "C" { #define PRECALL 166 #define CALL 171 #define KW_NAMES 172 +#define POP_JUMP_BACKWARD_IF_NOT_NONE 173 +#define POP_JUMP_BACKWARD_IF_NONE 174 #define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADD_FLOAT 4 #define BINARY_OP_ADD_INT 5 @@ -181,9 +183,9 @@ extern "C" { #define STORE_SUBSCR_DICT 168 #define STORE_SUBSCR_LIST_INT 169 #define UNPACK_SEQUENCE_ADAPTIVE 170 -#define UNPACK_SEQUENCE_LIST 173 -#define UNPACK_SEQUENCE_TUPLE 174 -#define UNPACK_SEQUENCE_TWO_TUPLE 175 +#define UNPACK_SEQUENCE_LIST 175 +#define UNPACK_SEQUENCE_TUPLE 176 +#define UNPACK_SEQUENCE_TWO_TUPLE 177 #define DO_TRACING 255 extern const uint8_t _PyOpcode_Caches[256]; @@ -196,8 +198,8 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 536870912U, 134234112U, - 4160U, - 0U, + 4163U, + 24576U, 0U, 0U, }; @@ -207,7 +209,7 @@ static const uint32_t _PyOpcode_Jump[8] = { 536870912U, 135118848U, 4163U, - 0U, + 24576U, 0U, 0U, }; @@ -338,9 +340,11 @@ const uint8_t _PyOpcode_Deopt[256] = { [MATCH_SEQUENCE] = MATCH_SEQUENCE, [NOP] = NOP, [POP_EXCEPT] = POP_EXCEPT, + [POP_JUMP_BACKWARD_IF_NONE] = POP_JUMP_BACKWARD_IF_NONE, + [POP_JUMP_BACKWARD_IF_NOT_NONE] = POP_JUMP_BACKWARD_IF_NOT_NONE, + [POP_JUMP_FORWARD_IF_NONE] = POP_JUMP_FORWARD_IF_NONE, + [POP_JUMP_FORWARD_IF_NOT_NONE] = POP_JUMP_FORWARD_IF_NOT_NONE, [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, [PRECALL] = PRECALL, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 45be177df76a92..072a81ff961641 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -400,6 +400,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.11a6 3490 (remove JUMP_IF_NOT_EXC_MATCH, add CHECK_EXC_MATCH) # Python 3.11a6 3491 (remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH, # add JUMP_BACKWARD_NO_INTERRUPT, make JUMP_NO_INTERRUPT virtual) +# Python 3.11a7 3492 (make POP_JUMP_IF_NONE/NOT_NONE relative) # Python 3.12 will start with magic number 3500 @@ -414,7 +415,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3491).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3492).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 97b580532cb94b..615b71a66dd8aa 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -148,8 +148,8 @@ def jabs_op(name, op, entries=0): haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) -jabs_op('POP_JUMP_IF_NOT_NONE', 128) -jabs_op('POP_JUMP_IF_NONE', 129) +jrel_op('POP_JUMP_FORWARD_IF_NOT_NONE', 128) +jrel_op('POP_JUMP_FORWARD_IF_NONE', 129) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('GET_AWAITABLE', 131) def_op('MAKE_FUNCTION', 132) # Flags @@ -197,6 +197,8 @@ def jabs_op(name, op, entries=0): 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) del def_op, name_op, jrel_op, jabs_op diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 2f78d42cc724a6..f13b440a5bc322 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -685,7 +685,11 @@ def test_widths(self): for opcode, opname in enumerate(dis.opname): if opname in ('BUILD_MAP_UNPACK_WITH_CALL', 'BUILD_TUPLE_UNPACK_WITH_CALL', - 'JUMP_BACKWARD_NO_INTERRUPT'): + 'JUMP_BACKWARD_NO_INTERRUPT', + 'POP_JUMP_FORWARD_IF_NONE', + 'POP_JUMP_BACKWARD_IF_NONE', + 'POP_JUMP_FORWARD_IF_NOT_NONE', + 'POP_JUMP_BACKWARD_IF_NOT_NONE'): continue with self.subTest(opname=opname): width = dis._OPNAME_WIDTH diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst new file mode 100644 index 00000000000000..54c9217451033e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-06-22-50-31.bpo-47120.mbfHs5.rst @@ -0,0 +1 @@ +Make :opcode:`POP_JUMP_IF_NONE` and :opcode:`POP_JUMP_IF_NOT_NONE` virtual, mapping to new relative jump opcodes. diff --git a/Python/ceval.c b/Python/ceval.c index 487e09bc664173..c00be2f2d4d7f2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3972,11 +3972,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(POP_JUMP_IF_NOT_NONE) { + TARGET(POP_JUMP_BACKWARD_IF_NOT_NONE) { PyObject *value = POP(); if (!Py_IsNone(value)) { Py_DECREF(value); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3984,11 +3984,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(POP_JUMP_IF_NONE) { + TARGET(POP_JUMP_FORWARD_IF_NOT_NONE) { + PyObject *value = POP(); + if (!Py_IsNone(value)) { + JUMPBY(oparg); + } + Py_DECREF(value); + DISPATCH(); + } + + TARGET(POP_JUMP_BACKWARD_IF_NONE) { PyObject *value = POP(); if (Py_IsNone(value)) { Py_DECREF(value); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3996,6 +4005,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } + TARGET(POP_JUMP_FORWARD_IF_NONE) { + PyObject *value = POP(); + if (Py_IsNone(value)) { + JUMPBY(oparg); + } + Py_DECREF(value); + DISPATCH(); + } + TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = TOP(); int err; diff --git a/Python/compile.c b/Python/compile.c index f04ba9ec50f6fd..a2bf0fbe42370f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -78,8 +78,10 @@ #define POP_BLOCK -4 #define JUMP -5 #define JUMP_NO_INTERRUPT -6 +#define POP_JUMP_IF_NONE -7 +#define POP_JUMP_IF_NOT_NONE -8 -#define MIN_VIRTUAL_OPCODE -6 +#define MIN_VIRTUAL_OPCODE -8 #define MAX_ALLOWED_OPCODE 254 #define IS_WITHIN_OPCODE_RANGE(opcode) \ @@ -87,11 +89,27 @@ #define IS_VIRTUAL_OPCODE(opcode) ((opcode) < 0) +#define IS_VIRTUAL_JUMP_OPCODE(opcode) \ + ((opcode) == JUMP || \ + (opcode) == JUMP_NO_INTERRUPT || \ + (opcode) == POP_JUMP_IF_NONE || \ + (opcode) == POP_JUMP_IF_NOT_NONE) + /* opcodes which are not emitted in codegen stage, only by the assembler */ #define IS_ASSEMBLER_OPCODE(opcode) \ ((opcode) == JUMP_FORWARD || \ (opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + (opcode) == JUMP_BACKWARD_NO_INTERRUPT || \ + (opcode) == POP_JUMP_FORWARD_IF_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_NONE || \ + (opcode) == POP_JUMP_FORWARD_IF_NOT_NONE || \ + (opcode) == POP_JUMP_BACKWARD_IF_NOT_NONE) + +#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) #define IS_TOP_LEVEL_AWAIT(c) ( \ @@ -156,7 +174,7 @@ is_block_push(struct instr *instr) static inline int is_jump(struct instr *i) { - return i->i_opcode == JUMP || + return IS_VIRTUAL_JUMP_OPCODE(i->i_opcode) || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); } @@ -1027,10 +1045,14 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_IF_FALSE_OR_POP: return jump ? 0 : -1; - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: + case POP_JUMP_BACKWARD_IF_NONE: + case POP_JUMP_FORWARD_IF_NONE: case POP_JUMP_IF_NONE: + case POP_JUMP_BACKWARD_IF_NOT_NONE: + case POP_JUMP_FORWARD_IF_NOT_NONE: case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: return -1; case LOAD_GLOBAL: @@ -7609,14 +7631,25 @@ normalize_jumps(struct assembler *a) } struct instr *last = &b->b_instr[b->b_iused-1]; assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - if (last->i_opcode == JUMP) { + if (is_jump(last)) { bool is_forward = last->i_target->b_visited == 0; - last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; - } - if (last->i_opcode == JUMP_NO_INTERRUPT) { - bool is_forward = last->i_target->b_visited == 0; - last->i_opcode = is_forward ? - JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + switch(last->i_opcode) { + case JUMP: + last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + break; + case JUMP_NO_INTERRUPT: + last->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + break; + case POP_JUMP_IF_NOT_NONE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_NOT_NONE : POP_JUMP_BACKWARD_IF_NOT_NONE; + break; + case POP_JUMP_IF_NONE: + last->i_opcode = is_forward ? + POP_JUMP_FORWARD_IF_NONE : POP_JUMP_BACKWARD_IF_NONE; + break; + } } } } @@ -7652,13 +7685,11 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) instr->i_oparg = instr->i_target->b_offset; if (is_relative_jump(instr)) { if (instr->i_oparg < bsize) { - assert(instr->i_opcode == JUMP_BACKWARD || - instr->i_opcode == JUMP_BACKWARD_NO_INTERRUPT); + assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg = bsize - instr->i_oparg; } else { - assert(instr->i_opcode != JUMP_BACKWARD); - assert(instr->i_opcode != JUMP_BACKWARD_NO_INTERRUPT); + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg -= bsize; } } @@ -8644,7 +8675,7 @@ apply_static_swaps(basicblock *block, int i) static bool jump_thread(struct instr *inst, struct instr *target, int opcode) { - assert(!IS_VIRTUAL_OPCODE(opcode) || opcode == JUMP); + assert(!IS_VIRTUAL_OPCODE(opcode) || IS_VIRTUAL_JUMP_OPCODE(opcode)); assert(is_jump(inst)); assert(is_jump(target)); // bpo-45773: If inst->i_target == target->i_target, then nothing actually diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 064aa060c84284..a0ce7601a2cc3f 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -127,8 +127,8 @@ static void *opcode_targets[256] = { &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, &&TARGET_PRECALL_NO_KW_TYPE_1, - &&TARGET_POP_JUMP_IF_NOT_NONE, - &&TARGET_POP_JUMP_IF_NONE, + &&TARGET_POP_JUMP_FORWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_FORWARD_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, @@ -172,6 +172,8 @@ static void *opcode_targets[256] = { &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, &&TARGET_CALL, &&TARGET_KW_NAMES, + &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_BACKWARD_IF_NONE, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, @@ -252,7 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING };