8000 gh-105775: Demote LOAD_CLOSURE to a pseudo-op · python/cpython@21d086e · GitHub
[go: up one dir, main page]

Skip to content

Commit 21d086e

Browse files
gh-105775: Demote LOAD_CLOSURE to a pseudo-op
This change demotes LOAD_CLOSURE from an instruction to a pseudo-instruction. This enables superinstruction formation, removal of checks for uninitialized variables, and frees up an instruction.
1 parent 4a6c84f commit 21d086e

File tree

14 files changed

+577
-580
lines changed

14 files changed

+577
-580
lines changed

Doc/library/dis.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,18 +1291,6 @@ iterations of the loop.
12911291
.. versionadded:: 3.11
12921292

12931293

1294-
.. opcode:: LOAD_CLOSURE (i)
1295-
1296-
Pushes a reference to the cell contained in slot ``i`` of the "fast locals"
1297-
storage. The name of the variable is ``co_fastlocalnames[i]``.
1298-
1299-
Note that ``LOAD_CLOSURE`` is effectively an alias for ``LOAD_FAST``.
1300-
It exists to keep bytecode a little more readable.
1301-
1302-
.. versionchanged:: 3.11
1303-
``i`` is no longer offset by the length of ``co_varnames``.
1304-
1305-
13061294
.. opcode:: LOAD_DEREF (i)
13071295

13081296
Loads the cell contained in slot ``i`` of the "fast locals" storage.
@@ -1725,6 +1713,18 @@ but are replaced by real opcodes or removed before bytecode is generated.
17251713
Undirected relative jump instructions which are replaced by their
17261714
directed (forward/backward) counterparts by the assembler.
17271715

1716+
.. opcode:: LOAD_CLOSURE (i)
1717+
1718+
Pushes a reference to the cell contained in slot ``i`` of the "fast locals"
1719+
storage.
1720+
1721+
Note that ``LOAD_CLOSURE`` is replaced with ``LOAD_FAST`` in the assembler.
1722+
It exists to keep bytecode a little more readable.
1723+
1724+
.. versionchanged:: 3.13
1725+
This opcode was demoted from full opcode to pseudo-instruction
1726+
1727+
17281728
.. opcode:: LOAD_METHOD
17291729

17301730
Optimized unbound method lookup. Emitted as a ``LOAD_ATTR`` opcode

Include/internal/pycore_opcode.h

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

Include/opcode.h

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

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ def _write_atomic(path, data, mode=0o666):
451451
# Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE)
452452
# Python 3.13a1 3554 (more efficient bytecodes for f-strings)
453453
# Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c)
454+
# Python 3.13a1 3556 (Remove LOAD_CLOSURE)
454455

455456
# Python 3.14 will start with 3600
456457

@@ -467,7 +468,7 @@ def _write_atomic(path, data, mode=0o666):
467468
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
468469
# in PC/launcher.c must also be updated.
469470

470-
MAGIC_NUMBER = (3555).to_bytes(2, 'little') + b'\r\n'
471+
MAGIC_NUMBER = (3556).to_bytes(2, 'little') + b'\r\n'
471472

472473
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
473474

Lib/opcode.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,6 @@ def pseudo_op(name, op, real_ops):
198198
jrel_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards)
199199
def_op('MAKE_CELL', 135)
200200
hasfree.append(135)
201-
def_op('LOAD_CLOSURE', 136)
202-
hasfree.append(136)
203201
def_op('LOAD_DEREF', 137)
204202
hasfree.append(137)
205203
def_op('STORE_DEREF', 138)
@@ -291,6 +289,7 @@ def pseudo_op(name, op, real_ops):
291289
pseudo_op('LOAD_SUPER_METHOD', 263, ['LOAD_SUPER_ATTR'])
292290
pseudo_op('LOAD_ZERO_SUPER_METHOD', 264, ['LOAD_SUPER_ATTR'])
293291
pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR'])
292+
pseudo_op('LOAD_CLOSURE', 267, ['LOAD_FAST'])
294293

295294
pseudo_op('STORE_FAST_MAYBE_NULL', 266, ['STORE_FAST'])
296295

Lib/test/test_dis.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ def foo(x):
685685
686686
%3d RESUME 0
687687
688-
%3d LOAD_CLOSURE 0 (y)
688+
%3d LOAD_FAST 0 (y)
689689
BUILD_TUPLE 1
690690
LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
691691
MAKE_FUNCTION
@@ -709,7 +709,7 @@ def foo(x):
709709
%3d RESUME 0
710710
711711
%3d LOAD_GLOBAL 1 (NULL + list)
712-
LOAD_CLOSURE 0 (x)
712+
LOAD_FAST 0 (x)
713713
BUILD_TUPLE 1
714714
LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>)
715715
MAKE_FUNCTION
@@ -1596,8 +1596,8 @@ def _prepare_test_cases():
15961596
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None),
15971597
Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=1, is_jump_target=False, positions=None),
15981598
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
1599-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None),
1600-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
1599+
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None),
1600+
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
16011601
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
16021602
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
16031603
Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
@@ -1624,10 +1624,10 @@ def _prepare_test_cases():
16241624
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=None, is_jump_target=False, positions=None),
16251625
Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
16261626
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=3, is_jump_target=False, positions=None),
1627-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
1628-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
1629-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
1630-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
1627+
Instruction(opname='LOAD_FAST', opcode=124, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
1628+
Instruction(opname='LOAD_FAST', opcode=124, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
1629+
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
1630+
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
16311631
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
16321632
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
16331633
Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Remove the LOAD_CLOSURE opcode and make it a pseudo-op instead. This enables
2+
3+
* Superinstruction formation
4+
* Removal of checks for uninitialized variables

PC/launcher.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ static PYC_MAGIC magic_values[] = {
12701270
/* Allow 50 magic numbers per version from here on */
12711271
{ 3450, 3499, L"3.11" },
12721272
{ 3500, 3549, L"3.12" },
1273+
{ 3550, 3599, L"3.13" },
12731274
{ 0 }
12741275
};
12751276

Python/bytecodes.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ dummy_func(
134134
// BEGIN BYTECODES //
135135
inst(NOP, (--)) {
136136
}
137-
137+
138138
inst(RESUME, (--)) {
139139
assert(tstate->cframe == &cframe);
140140
assert(frame == cframe.current_frame);
@@ -177,12 +177,9 @@ dummy_func(
177177
}
178178
}
179179

180-
inst(LOAD_CLOSURE, (-- value)) {
181-
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
182-
value = GETLOCAL(oparg);
183-
ERROR_IF(value == NULL, unbound_local_error);
184-
Py_INCREF(value);
185-
}
180+
pseudo(LOAD_CLOSURE) = {
181+
LOAD_FAST,
182+
};
186183

187184
inst(LOAD_FAST_CHECK, (-- value)) {
188185
value = GETLOCAL(oparg);
@@ -195,7 +192,7 @@ dummy_func(
195192
assert(value != NULL);
196193
Py_INCREF(value);
197194
}
198-
195+
199196
inst(LOAD_FAST_AND_CLEAR, (-- value)) {
200197
value = GETLOCAL(oparg);
201198
// do not use SETLOCAL here, it decrefs the old value

Python/compile.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,9 +843,11 @@ stack_effect(int opcode, int oparg, int jump)
843843
* of __(a)enter__ and push 2 values before jumping to the handler
844844
* if an exception be raised. */
845845
return jump ? 1 : 0;
846-
846+
847847
case STORE_FAST_MAYBE_NULL:
848848
return -1;
849+
case LOAD_CLOSURE:
850+
return 1;
849851
case LOAD_METHOD:
850852
return 1;
851853
case LOAD_SUPER_METHOD:

Python/flowgraph.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,6 +2078,10 @@ _PyCfg_ConvertPseudoOps(basicblock *entryblock)
20782078
assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP));
20792079
INSTR_SET_OP0(instr, NOP);
20802080
}
2081+
else if (instr->i_opcode == LOAD_CLOSURE) {
2082+
assert(SAME_OPCODE_METADATA(LOAD_CLOSURE, LOAD_FAST));
2083+
instr->i_opcode = LOAD_FAST;
2084+
}
20812085
else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
20822086
assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST));
20832087
instr->i_opcode = STORE_FAST;

0 commit comments

Comments
 (0)
0