Bytecode VM v3

hard · compilers, virtual machine, bytecode, gc

Bytecode VM v3

Implement a stack-based virtual machine with closures, arrays, maps, indexing, and mark-sweep GC.

API

func NewVM() *VM
func (vm *VM) Run(bc Bytecode) (Value, error)
func (vm *VM) GC()
func (vm *VM) HeapCount() int

Run should execute bc.Main. It should start from a clean VM state (fresh stack and environment).

Bytecode types

Use the provided types:

  • Bytecode with Main []Instr and Functions []Function
  • Function with ID, Name, Params, and Code []Instr
  • Instr with Op, Int, and Str

Value types

Use the provided Value struct with kinds:

  • number
  • string
  • bool
  • nil
  • array
  • map
  • closure

Arrays, maps, and closures are heap objects managed by GC.

Runtime rules

Truthiness

  • false and nil are falsey
  • everything else is truthy

Arithmetic / comparison

  • + - * / work on numbers
  • + also supports string concatenation when both operands are strings
  • < <= > >= work on numbers
  • == / != compare by type and value (arrays/maps/closures compare by identity)

Type mismatches should return a non-nil error.

Variables and scopes

  • DEFINE_VAR / DEFINE_CONST create bindings in the current scope
  • STORE updates the nearest existing binding (error if const)
  • LOAD reads the nearest existing binding
  • ENTER_SCOPE / EXIT_SCOPE push and pop scope frames

Functions and closures

  • MAKE_CLOSURE <id> captures the current environment and pushes a closure value.
  • CALL <arity> pops arguments and a callee. The callee must be a closure.
  • Create a new environment for each call with parent = closure environment.
  • Bind parameters left-to-right.
  • If a function returns without RETURN, its result is nil.

Arrays and maps

  • MAKE_ARRAY <n> pops n values and creates an array (preserve order).
  • MAKE_MAP <n> pops 2n values (key then value) and creates a map.
  • Map keys must be number, string, bool, or nil.

Indexing

  • GET_INDEX pops index and target:
    • array: index must be number, in range
    • map: key must be hashable, missing key returns nil
  • SET_INDEX pops value, index, target:
    • array: index must be number, in range
    • map: key must be hashable, sets or overwrites

Program result

After executing Main, return the top of the stack if present; otherwise return nil.

GC

Implement mark-sweep GC over heap objects.

  • Roots include the value stack and all reachable environments.
  • Closures keep their captured environments alive.
  • HeapCount returns the number of live heap objects currently tracked.

Notes

  • Use absolute jump targets.
  • Keep the VM readable and straightforward.
Run tests to see results
No issues detected