Bytecode & VM: Making It Run

Lesson, slides, and applied problem sets.

View Slides

Lesson

Bytecode & VM: Making It Run

Why this module exists

This is the "compiler is real" moment. We turn ASTs into bytecode and then execute that bytecode in a VM. The bytecode is a separate artifact: the compiler produces it, and the VM consumes it.


1) Stack machine recap

A stack machine evaluates by pushing values and applying operations.

For 1 + 2 * 3:

PUSH_NUM 1
PUSH_NUM 2
PUSH_NUM 3
MUL
ADD

2) Statements and control flow

We add instructions for:

  • variable definitions (DEFINE_VAR, DEFINE_CONST)
  • assignments (STORE)
  • blocks (ENTER_SCOPE, EXIT_SCOPE)
  • control flow (JUMP, JUMP_IF_FALSE)
  • function calls (CALL, RETURN)

3) Bytecode as a real target

The compiler emits a Bytecode object:

  • Main instructions for top-level code
  • Functions table with each function's bytecode

The VM loads this bytecode and executes it. That separation is what makes the compiler "honest."


4) Truthiness and runtime errors

The VM defines truthiness:

  • false and nil are falsey
  • everything else is truthy

If an operation uses incompatible types (like "hi" - 1), the VM reports a runtime error.


5) Open-ended paths

You could extend this into:

  • a bytecode file format
  • a register-based VM
  • bytecode optimizations
  • JIT compilation

Module Items