z-go-interp-perf

Installation
SKILL.md

Go interpreter/VM performance

In a Go VM the hot costs are rarely "dispatch architecture" — they are clocks, atomics, locks, and interface boxing executed per instruction or per host call. Remove those before considering an encoding rewrite; on one production VM, half of the flagship benchmark's runtime was clock + lock overhead.

Dispatch-loop overhead anatomy

Profile-verified shares from a stack VM running a recursive workload — check these before anything structural:

  • ctx.Err() per instruction on a deadline context ≈ 10% of runtime; an unconditional time.Now at call/loop opcodes ≈ 26%. Poll cancellation on an N-instruction budget (~128), and compute the deadline lazily at the first poll so short runs never touch the clock. Precedents: goja checks an atomic interrupt flag with an external time.AfterFunc; wasmtime's "slacked fuel" checks only at function entry and loop back-edges.
  • Per-op atomic charging (metering, stats) — batch into a VM-local accumulator settled at poll boundaries, run exit, and host-call dispatch.
  • RWMutex read locks surface in pprof as atomic.Int32.Add. Attribute with go tool pprof -peek 'Int32.*Add' before assuming counters.
  • Validate chunks at load time so the hot loop drops per-instruction bounds checks — then every opcode carrying a jump, slot, or constant operand needs a validation case, including exception-handler addresses and fall-off-end (the last instruction must be non-fall-through). Re-audit on every new opcode; this bites twice otherwise.

Boxing

Prebox only values that allocate on the measured VM path. Current gc already has static storage for bools and some small integer representations; nonescaping conversions may use the stack or disappear. Negative values do not universally allocate. Compare representative concrete types and escape paths before adding a cache; verification belongs to [[z-go-performance]] "Verify the premise first".

Global/name resolution

Installs
12
First Seen
Aug 12, 2026