8000 bpo-43693: Compute deref offsets in compiler by markshannon · Pull Request #25152 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-43693: Compute deref offsets in compiler #25152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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),
8000 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
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:
D966 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.

0