Internals
Architecture
NanoVM follows Fabrice Bellard’s approach to high-performance WASM interpreters: a dense, monolithic dispatch loop with almost no host boundary.
Design principles
- Monolithic exec() — dense dispatch compiles to a WASM br_table (O(1) jump tables). Source is split across files with #[inline(always)]; fat LTO fuses everything into a single function.
- #![no_std] Rust — no standard library, no heap allocation in the hot path, zero dependencies except libm.
- Minimal host boundary — five WASM imports, ~30 exports; filesystem I/O goes through shared memory, not per-instruction callbacks.
- Cooperative threading — clone / futex multithreading with context switching at syscall boundaries.
Execution model
The interpreter fetches and decodes one instruction at a time and dispatches through the br_table. It runs uninterrupted until it hits a syscall boundary, where control returns to the host only if the syscall needs it.
Memory
Guest memory is a flat region managed with brk and mmap. A bump allocator handles the VM’s own small allocations; the guest program manages its own heap exactly as it would on real Linux.
The VM struct
The whole machine state is a single #[repr(C)] struct — 12,680 bytes — holding registers, CSRs, the memory map, the thread table and FS state.
File
Responsibility
cpu.rs
RV64GC interpreter loop
decode.rs
instruction field extraction
syscall.rs
Linux syscall dispatch (~80)
mem.rs
guest memory read / write
elf.rs
ELF loader (segments, argv/envp/auxv)
types.rs
the 12,680-byte VM struct