Description
This is a refinement of #37, and occurred to me when discussing https://bugs.python.org/issue43693
Rather than simply tacking the cells on to the end of locals, why not interleave them?
Arguments that escape could then be left in their "natural" position.
Doing so would simplify frame creation code a lot, as it wouldn't need to know about cell variables at all.
Example:
def f(a):
def g():
return a
return g
When creating the frame for f
, frame creation code (e.g. _PyEval_MakeFrameVector
) has to know about cell variables, free variables and which cell variables are arguments. That could all be handled in the compiler.
Currently the bytecode for f
above is:
2 0 LOAD_CLOSURE 0 (a)
2 BUILD_TUPLE 1
4 LOAD_CONST 1 (<code object g at 0x7f8075837c60, file "<stdin>", line 2>)
6 LOAD_CONST 2 ('f.<locals>.g')
8 MAKE_FUNCTION 8 (closure)
10 STORE_FAST 1 (g)
4 12 LOAD_FAST 1 (g)
14 RETURN_VALUE
The compiler knows that a
escapes f
, so why not use that knowledge?
By boxing a
in the bytecode, closures and normal functions can be treated the same at runtime.
We only need to add one extra instruction in this case:
2 0 MAKE_CELL 0 (a)
2 LOAD_CLOSURE 0 (a)
4 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object g at 0x7f8075837c60, file "<stdin>", line 2>)
8 LOAD_CONST 2 ('f.<locals>.g')
10 MAKE_FUNCTION 8 (closure)
12 STORE_FAST 1 (g)
4 12 LOAD_FAST 1 (g)
14 RETURN_VALUE
(The code for g
is unchanged)
Metadata
Metadata
Assignees
Type
Projects
Status