I've noticed an intriguing peculiarity in Python's bytecode here.
The CONTINUE_LOOP
opcode takes in a target
argument that denotes the instruction of the loop to continue executing, which is a FOR_ITER
instruction.
The BREAK_LOOP
opcode, however, does not do this. It only breaks out of the current (innermost) loop.
What is the reason behind this? Why should it be possible to continue
but not break
an outer loop?
You are misunderstanding the target. The value is not needed to handle nested loops. Instead, the target marks the point in the bytecode stream to move to after the instruction. BREAK
doesn't need such a target because that value is already defined elsewhere.
BREAK_LOOP
ends a loop and thus execution continues after the loop. The SETUP_LOOP
instruction has defined the endpoint already, so the interpreter doesn't need any additional information to execute this opcode.
CONTINUE_LOOP
on the other hand needs to be told where to continue to. In most loops, a JUMP_ABSOLUTE
opcode is used, and CONTINUE_LOOP
echoes that instruction here. CONTINUE_LOOP
records a bit more information to handle try
statements (to track stack unwinding).
In the evaluation loop, exception handling (try: ... except:
and try
: ... finally:
) as well as context managers (with ...:
and async with ...:
) use a generalised concept of a frame block, which has an exit point recorded for it, which is what the BREAK_LOOP
instruction relies on here. Not having to track an offset is simpler this way and avoids the compiler and evaluation loop having to repeat themselves (the exit point is used for other scenarios too, not just the break
statement).
But jumps are more generic and so their offsets are easier to track tied to the instruction itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With