Skip to content
Chunks of Bytecode
step 1/3

Reading — step 1 of 3

The Bytecode Representation

~2 min readBytecode Virtual Machine

Chunks of Bytecode

We now shift from the tree-walk interpreter to building a bytecode virtual machine. The first step: designing the bytecode format itself.

Why Bytecode?

Tree-walk interpreters are slow because they traverse heap-allocated AST nodes. A bytecode VM is faster because:

  • Bytecode is a flat array of bytes — excellent cache locality
  • No pointer chasing — instructions are sequential
  • The dispatch loop is tight and branch-predictor friendly
  • We can apply optimizations during compilation

CPython, Lua, Ruby (since 1.9), and Erlang all use bytecode VMs. V8 also compiles to bytecode (Ignition) before optionally JIT-compiling hot functions.

The Chunk

A chunk is our unit of bytecode. It contains:

Chunk {
    code:      byte[]    // the bytecode instructions
    constants: Value[]   // constant pool (literals)
    lines:     int[]     // line number for each byte (for errors)
}

The code array holds opcodes (one byte each) and their operands. The constants array holds literal values referenced by index. The lines array maps each byte offset to a source line number for error reporting.

Opcodes

Each instruction starts with a one-byte opcode:

OP_CONSTANT  0x00   // push a constant (followed by 1-byte index)
OP_RETURN    0x01   // return from function
OP_NEGATE    0x02   // negate top of stack
OP_ADD       0x03   // pop two, push sum
OP_SUBTRACT  0x04
OP_MULTIPLY  0x05
OP_DIVIDE    0x06

The Constant Pool

Numbers and strings are too large to embed directly in the bytecode stream. Instead, we store them in the constant pool and reference them by index:

chunk.constants = [42.0, "hello"]
chunk.code = [OP_CONSTANT, 0, OP_CONSTANT, 1, OP_ADD, OP_RETURN]

OP_CONSTANT 0 means "push constants[0] (42.0) onto the stack."

Disassembly

A disassembler converts raw bytes back into human-readable form — essential for debugging:

0000    1 OP_CONSTANT    0 '42'
0002    | OP_CONSTANT    1 '3.14'
0004    | OP_ADD
0005    | OP_RETURN

This shows: byte offset, line number, opcode name, and operand details.

Your Task

Build the Chunk data structure, implement adding constants and emitting opcodes, and write a disassembler that prints bytecode in human-readable form.

Discussion

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

Sign in to post a comment or reply.

Loading…