Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Python's CONTINUE_LOOP allow an outer loop, when BREAK_LOOP doesn't?

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?

like image 324
user541686 Avatar asked Jan 04 '23 22:01

user541686


1 Answers

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.

like image 172
Martijn Pieters Avatar answered Jan 14 '23 13:01

Martijn Pieters