Skip to content
Compiling Control Flow (Jumps)
step 1/3

Reading — step 1 of 3

Jump Instructions for Control Flow

~2 min readCompiling to Bytecode

Compiling Control Flow (Jumps)

Control flow in bytecode is implemented with jump instructions — instructions that change the instruction pointer instead of incrementing it sequentially.

Jump Instructions

OP_JUMP            // unconditional forward jump
OP_JUMP_IF_FALSE   // jump if top of stack is falsy (does NOT pop)
OP_LOOP            // unconditional backward jump

Each jump instruction has a 16-bit operand: the offset to jump by.

Compiling If/Else

if (condition) { thenBranch } else { elseBranch }

Compiles to:

[compile condition]
OP_JUMP_IF_FALSE → elseOffset
OP_POP                        // pop condition (then path)
[compile thenBranch]
OP_JUMP → endOffset
elseOffset:
OP_POP                        // pop condition (else path)
[compile elseBranch]
endOffset:

The Backpatching Problem

When we emit OP_JUMP_IF_FALSE, we do not yet know the offset — we have not compiled the then-branch yet. The solution: backpatching.

  1. Emit the jump with a placeholder offset (0xFFFF)
  2. Record the position of the placeholder
  3. Compile the body
  4. Calculate the actual offset (current position - placeholder position)
  5. Overwrite the placeholder with the real offset
emitJump(opcode):
    emit(opcode)
    emit(0xFF)    // placeholder high byte
    emit(0xFF)    // placeholder low byte
    return currentOffset - 2   // position to patch

patchJump(offset):
    jump = currentOffset - offset - 2
    code[offset] = (jump >> 8) & 0xFF
    code[offset + 1] = jump & 0xFF

Compiling While Loops

while (condition) { body }

Compiles to:

loopStart:
[compile condition]
OP_JUMP_IF_FALSE → exitOffset
OP_POP
[compile body]
OP_LOOP → loopStart          // backward jump
exitOffset:
OP_POP

OP_LOOP uses a negative offset to jump backward. The compiler calculates this as currentOffset - loopStart + 2.

Compiling For Loops

As with the tree-walk interpreter, for loops desugar to while loops. The compiler handles the desugaring directly during compilation.

Your Task

Implement jump instructions, backpatching, and compile if/else, while, and for loops to bytecode.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…