Skip to content
Merged
Prev Previous commit
Next Next commit
Preserve the LOAD_CLOSURE opcode as an alias for LOAD_FAST.
  • Loading branch information
ericsnowcurrently committed Jun 3, 2021
commit 775d4dbd3f425c24c2105feb6d678a79055a300d
28 changes: 14 additions & 14 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1043,20 +1043,7 @@ All of the following opcodes use their arguments.

.. opcode:: LOAD_FAST (var_num)

Pushes a reference to a local variable or closure cell onto the stack.
The corresponding variable name is
``(co_varnames + co_cellvars + co_freevars)[var_num]``.

For closures, note that ``LOAD_FAST`` loads the cell object contained
in the corresponding slot of the cell and free variable storage,
at index ``var_num - len(co_varnames)``.
In contrast, ``LOAD_DEREF`` gets the object the cell references.

Use of ``LOAD_FAST`` for closures is primarily to share cells objects
from an outer closure when creating an inner one with ``MAKE_FUNCTION``.

.. versionchanged:: 3.10
Closure cells are handled here now instead of ``LOAD_CLOSURE`` (removed).
Pushes a reference to the local ``co_varnames[var_num]`` onto the stack.


.. opcode:: STORE_FAST (var_num)
Expand All @@ -1069,6 +1056,19 @@ All of the following opcodes use their arguments.
Deletes local ``co_varnames[var_num]``.


.. opcode:: LOAD_CLOSURE (i)

Pushes a reference to the cell contained in slot ``i - len(co_varnames)``
of the cell and free variable storage. The name of the variable is
``(co_varnames + co_cellvars + co_freevars)[i]``.

Note that ``LOAD_CLOSURE`` is effectively an alias for ``LOAD_FAST``.
It exists to keep bytecode a little more readable.

.. versionchanged:: 3.10
``i`` is offset by the length of ``co_varnames``.


.. opcode:: LOAD_DEREF (i)

Loads the cell contained in slot ``i - len(co_varnames)`` of the cell
Expand Down
1 change: 1 addition & 0 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ def jabs_op(name, op):
def_op('MAKE_FUNCTION', 132) # Flags
def_op('BUILD_SLICE', 133) # Number of items

def_op('LOAD_CLOSURE', 135)
hasfree.append(135)
def_op('LOAD_DEREF', 136)
hasfree.append(136)
def_op('STORE_DEREF', 137)
Expand Down
16 changes: 8 additions & 8 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ def foo(x):
return foo

dis_nested_0 = """\
%3d 0 LOAD_FAST 2 (y)
%3d 0 LOAD_CLOSURE 2 (y)
2 BUILD_TUPLE 1
4 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
6 LOAD_CONST 2 ('_h.<locals>.foo')
Expand All @@ -444,7 +444,7 @@ def foo(x):

dis_nested_1 = """%s
Disassembly of <code object foo at 0x..., file "%s", line %d>:
%3d 0 LOAD_FAST 1 (x)
%3d 0 LOAD_CLOSURE 1 (x)
2 BUILD_TUPLE 1
4 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
6 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>')
Expand Down Expand Up @@ -962,8 +962,8 @@ def jumpy():
Instruction = dis.Instruction
expected_opinfo_outer = [
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=3, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=4, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=10, starts_line=None, is_jump_target=False),
Expand All @@ -985,10 +985,10 @@ def jumpy():

expected_opinfo_f = [
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=5, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=6, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=3, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=4, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=5, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=6, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=14, starts_line=None, is_jump_target=False),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Compute cell offsets relative to locals in compiler. Allows the interpreter
to treats locals and cells a single array, which is slightly more efficient.

Delete the LOAD_CLOSURE bytecode.
Also make the LOAD_CLOSURE opcode an alias for LOAD_FAST. Preserving
LOAD_CLOSURE helps keep bytecode a bit more readable.
2 changes: 2 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
DISPATCH();
}

/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
case TARGET(LOAD_CLOSURE):
case TARGET(LOAD_FAST): {
PyObject *value = GETLOCAL(oparg);
if (value == NULL) {
Expand Down
7 changes: 2 additions & 5 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@
#define SETUP_WITH 253
#define POP_BLOCK 252

/* Artificial instruction, will be converted to LOAD_FAST */
#define LOAD_CLOSURE 251

#define IS_TOP_LEVEL_AWAIT(c) ( \
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
&& (c->u->u_ste->ste_type == ModuleBlock))
Expand Down Expand Up @@ -1188,6 +1185,8 @@ stack_effect(int opcode, int oparg, int jump)
return -1;

/* Closures */
case LOAD_CLOSURE:
return 1;
case LOAD_DEREF:
case LOAD_CLASSDEREF:
return 1;
Expand Down Expand Up @@ -7444,8 +7443,6 @@ offset_derefs(basicblock *entryblock, int nlocals)
struct instr *inst = &b->b_instr[i];
switch(inst->i_opcode) {
case LOAD_CLOSURE:
inst->i_opcode = LOAD_FAST;
/* fall through */
case LOAD_DEREF:
case STORE_DEREF:
case DELETE_DEREF:
Expand Down
2 changes: 1 addition & 1 deletion Python/importlib.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Python/importlib_external.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Python/opcode_targets.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.