bpo-32949: Better bytecodes for "with" statement. by markshannon · Pull Request #5112 · python/cpython
This PR cleans up the interpreter by generating two different code paths for exiting a with statement. One for normal exits and another for the exceptional case.
For this function:
The bytecode generated changes from:
2 0 LOAD_GLOBAL 0 (a)
2 SETUP_WITH 10 (to 14)
4 POP_TOP
3 6 LOAD_GLOBAL 1 (b)
8 POP_TOP
10 POP_BLOCK
12 BEGIN_FINALLY
>> 14 WITH_CLEANUP_START
16 WITH_CLEANUP_FINISH
18 END_FINALLY
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
to
2 0 LOAD_GLOBAL 0 (a)
2 SETUP_WITH 20 (to 24)
4 POP_TOP
3 6 LOAD_GLOBAL 1 (b)
8 POP_TOP
10 POP_BLOCK
12 LOAD_CONST 0 (None)
14 DUP_TOP
16 DUP_TOP
18 CALL_FUNCTION 3
20 POP_TOP
22 JUMP_FORWARD 16 (to 40)
>> 24 WITH_EXCEPT_START
26 POP_JUMP_IF_TRUE 30
28 RERAISE
>> 30 POP_TOP
32 POP_TOP
34 POP_TOP
36 POP_EXCEPT
38 POP_TOP
>> 40 LOAD_CONST 0 (None)
42 RETURN_VALUE
Although this superficially appears worse, consider the non-exceptional path, after the POP_BLOCK bytecode.
before:
12 BEGIN_FINALLY
>> 14 WITH_CLEANUP_START
16 WITH_CLEANUP_FINISH
18 END_FINALLY
after:
12 LOAD_CONST 0 (None)
14 DUP_TOP
16 DUP_TOP
18 CALL_FUNCTION 3
20 POP_TOP
22 JUMP_FORWARD 16 (to 40)
we have replaced several complex and inefficient bytecodes with a few more simpler and faster bytecodes.