Skip to content

Commit a00518d

Browse files
authored
bpo-47120: Replace the JUMP_ABSOLUTE opcode by the relative JUMP_BACKWARD (GH-32115)
1 parent b36d222 commit a00518d

File tree

15 files changed

+147
-113
lines changed

15 files changed

+147
-113
lines changed

Doc/library/dis.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,13 @@ iterations of the loop.
895895
Increments bytecode counter by *delta*.
896896

897897

898+
.. opcode:: JUMP_BACKWARD (delta)
899+
900+
Decrements bytecode counter by *delta*.
901+
902+
.. versionadded:: 3.11
903+
904+
898905
.. opcode:: POP_JUMP_IF_TRUE (target)
899906

900907
If TOS is true, sets the bytecode counter to *target*. TOS is popped.
@@ -974,11 +981,6 @@ iterations of the loop.
974981
.. versionadded:: 3.1
975982

976983

977-
.. opcode:: JUMP_ABSOLUTE (target)
978-
979-
Set bytecode counter to *target*.
980-
981-
982984
.. opcode:: JUMP_NO_INTERRUPT (target)
983985

984986
Set bytecode counter to *target*. Do not check for interrupts.

Doc/whatsnew/3.11.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ CPython bytecode changes
522522

523523
* :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception.
524524

525+
* Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`.
525526

526527
Deprecated
527528
==========

Include/opcode.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/dis.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
LOAD_CONST = opmap['LOAD_CONST']
3131
LOAD_GLOBAL = opmap['LOAD_GLOBAL']
3232
BINARY_OP = opmap['BINARY_OP']
33+
JUMP_BACKWARD = opmap['JUMP_BACKWARD']
3334

3435
CACHE = opmap["CACHE"]
3536

@@ -441,7 +442,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
441442
argval = arg*2
442443
argrepr = "to " + repr(argval)
443444
elif op in hasjrel:
444-
argval = offset + 2 + arg*2
445+
signed_arg = -arg if op == JUMP_BACKWARD else arg
446+
argval = offset + 2 + signed_arg*2
445447
argrepr = "to " + repr(argval)
446448
elif op in haslocal or op in hasfree:
447449
argval, argrepr = _get_name_info(arg, varname_from_oparg)
@@ -566,6 +568,8 @@ def findlabels(code):
566568
for offset, op, arg in _unpack_opargs(code):
567569
if arg is not None:
568570
if op in hasjrel:
571+
if op == JUMP_BACKWARD:
572+
arg = -arg
569573
label = offset + 2 + arg*2
570574
elif op in hasjabs:
571575
label = arg*2

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ def _write_atomic(path, data, mode=0o666):
396396
# Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
397397
# Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism)
398398
# Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL)
399+
# Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE)
399400

400401
# Python 3.12 will start with magic number 3500
401402

@@ -410,7 +411,7 @@ def _write_atomic(path, data, mode=0o666):
410411
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
411412
# in PC/launcher.c must also be updated.
412413

413-
MAGIC_NUMBER = (3488).to_bytes(2, 'little') + b'\r\n'
414+
MAGIC_NUMBER = (3489).to_bytes(2, 'little') + b'\r\n'
414415
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
415416

416417
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,9 @@ def jabs_op(name, op, entries=0):
128128
hascompare.append(107)
129129
name_op('IMPORT_NAME', 108) # Index in name list
130130
name_op('IMPORT_FROM', 109) # Index in name list
131-
jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
131+
jrel_op('JUMP_FORWARD', 110) # Number of words to skip
132132
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
133133
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
134-
jabs_op('JUMP_ABSOLUTE', 113) # ""
135134
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
136135
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
137136
name_op('LOAD_GLOBAL', 116, 5) # Index in name list
@@ -166,6 +165,7 @@ def jabs_op(name, op, entries=0):
166165
hasfree.append(138)
167166
def_op('DELETE_DEREF', 139)
168167
hasfree.append(139)
168+
jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)
169169

170170
def_op('CALL_FUNCTION_EX', 142) # Flags
171171

@@ -259,8 +259,8 @@ def jabs_op(name, op, entries=0):
259259
"COMPARE_OP_INT_JUMP",
260260
"COMPARE_OP_STR_JUMP",
261261
],
262-
"JUMP_ABSOLUTE": [
263-
"JUMP_ABSOLUTE_QUICK",
262+
"JUMP_BACKWARD": [
263+
"JUMP_BACKWARD_QUICK",
264264
],
265265
"LOAD_ATTR": [
266266
"LOAD_ATTR_ADAPTIVE",

Lib/test/test_dis.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def bug708901():
149149
>> FOR_ITER 2 (to 40)
150150
STORE_FAST 0 (res)
151151
152-
%3d JUMP_ABSOLUTE 17 (to 34)
152+
%3d JUMP_BACKWARD 3 (to 34)
153153
154154
%3d >> LOAD_CONST 0 (None)
155155
RETURN_VALUE
@@ -354,7 +354,7 @@ def bug42562():
354354
BINARY_OP 13 (+=)
355355
STORE_NAME 0 (x)
356356
357-
2 JUMP_ABSOLUTE 4 (to 8)
357+
2 JUMP_BACKWARD 6 (to 8)
358358
"""
359359

360360
dis_traceback = """\
@@ -574,7 +574,7 @@ def foo(x):
574574
LOAD_FAST 1 (z)
575575
BINARY_OP 0 (+)
576576
LIST_APPEND 2
577-
JUMP_ABSOLUTE 4 (to 8)
577+
JUMP_BACKWARD 8 (to 8)
578578
>> RETURN_VALUE
579579
""" % (dis_nested_1,
580580
__file__,
@@ -1227,14 +1227,14 @@ def _prepare_test_cases():
12271227
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None),
12281228
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None),
12291229
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),
1230-
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
1230+
Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
12311231
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None),
12321232
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None),
12331233
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None),
12341234
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),
12351235
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None),
12361236
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None),
1237-
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
1237+
Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
12381238
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None),
12391239
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),
12401240
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 @@ def _prepare_test_cases():
12551255
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None),
12561256
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None),
12571257
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),
1258-
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=64, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
1258+
Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
12591259
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None),
12601260
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None),
12611261
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None),

Lib/test/test_peepholer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def f():
127127
return list
128128
for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
129129
self.assertNotInBytecode(f, elem)
130-
for elem in ('JUMP_ABSOLUTE',):
130+
for elem in ('JUMP_BACKWARD',):
131131
self.assertInBytecode(f, elem)
132132
self.check_lnotab(f)
133133

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Replaced :opcode:`JUMP_ABSOLUTE` by the relative jump :opcode:`JUMP_BACKWARD`.
2+

Objects/frameobject.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ mark_stacks(PyCodeObject *code_obj, int len)
237237
stacks[i+1] = next_stack;
238238
break;
239239
}
240-
case JUMP_ABSOLUTE:
241240
case JUMP_NO_INTERRUPT:
242241
j = get_arg(code, i);
243242
assert(j < len);
@@ -264,6 +263,12 @@ mark_stacks(PyCodeObject *code_obj, int len)
264263
assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
265264
stacks[j] = next_stack;
266265
break;
266+
case JUMP_BACKWARD:
267+
j = i + 1 - get_arg(code, i);
268+
assert(j >= 0);
269+
assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
270+
stacks[j] = next_stack;
271+
break;
267272
case GET_ITER:
268273
case GET_AITER:
269274
next_stack = push_value(pop_value(next_stack), Iterator);

Programs/test_frozenmain.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/ceval.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,7 +2218,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
22182218
Py_DECREF(v);
22192219
if (err != 0)
22202220
goto error;
2221-
PREDICT(JUMP_ABSOLUTE);
2221+
PREDICT(JUMP_BACKWARD_QUICK);
22222222
DISPATCH();
22232223
}
22242224

@@ -2230,7 +2230,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
22302230
Py_DECREF(v);
22312231
if (err != 0)
22322232
goto error;
2233-
PREDICT(JUMP_ABSOLUTE);
2233+
PREDICT(JUMP_BACKWARD_QUICK);
22342234
DISPATCH();
22352235
}
22362236

@@ -3396,7 +3396,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
33963396
if (_PyDict_SetItem_Take2((PyDictObject *)map, key, value) != 0) {
33973397
goto error;
33983398
}
3399-
PREDICT(JUMP_ABSOLUTE);
3399+
PREDICT(JUMP_BACKWARD_QUICK);
34003400
DISPATCH();
34013401
}
34023402

@@ -3926,6 +3926,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
39263926
DISPATCH();
39273927
}
39283928

3929+
TARGET(JUMP_BACKWARD) {
3930+
_PyCode_Warmup(frame->f_code);
3931+
JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK);
3932+
}
3933+
39293934
TARGET(POP_JUMP_IF_FALSE) {
39303935
PREDICTED(POP_JUMP_IF_FALSE);
39313936
PyObject *cond = POP();
@@ -4053,12 +4058,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
40534058
DISPATCH();
40544059
}
40554060

4056-
TARGET(JUMP_ABSOLUTE) {
4057-
PREDICTED(JUMP_ABSOLUTE);
4058-
_PyCode_Warmup(frame->f_code);
4059-
JUMP_TO_INSTRUCTION(JUMP_ABSOLUTE_QUICK);
4060-
}
4061-
40624061
TARGET(JUMP_NO_INTERRUPT) {
40634062
/* This bytecode is used in the `yield from` or `await` loop.
40644063
* If there is an interrupt, we want it handled in the innermost
@@ -4069,10 +4068,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
40694068
DISPATCH();
40704069
}
40714070

4072-
TARGET(JUMP_ABSOLUTE_QUICK) {
4073-
PREDICTED(JUMP_ABSOLUTE_QUICK);
4071+
TARGET(JUMP_BACKWARD_QUICK) {
4072+
PREDICTED(JUMP_BACKWARD_QUICK);
40744073
assert(oparg < INSTR_OFFSET());
4075-
JUMPTO(oparg);
4074+
JUMPBY(-oparg);
40764075
CHECK_EVAL_BREAKER();
40774076
DISPATCH();
40784077
}

0 commit comments

Comments
 (0)