TinyWasm follows the general runtime model described in the WebAssembly specification, but lowers validated WebAssembly into a compact internal instruction format before execution.
- Values are stored in untyped stacks:
stack_32fori32,f32,funcref, andexternrefstack_64fori64andf64stack_128forv128
- Locals are stored directly in the value stacks. Each
CallFramestores alocals_base, and local instructions index from that base. - Structured control flow (
block,loop,if,br*) is lowered during parsing to jump-oriented internal instructions such asJump,JumpIfZero,BranchTable*,DropKeep*, andReturn. - Execution is a single iterative interpreter loop over the lowered instruction stream.
TinyWasm does not interpret WebAssembly instructions directly. During parsing and validation, WebAssembly is translated into TinyWasm's internal bytecode format.
This internal representation is designed to make execution simpler and cheaper:
- structured control flow is resolved ahead of time
- stack effects are made explicit
- common instruction sequences can be fused into superinstructions
- modules can optionally be serialized as
.twasmfor reuse
During parsing, a peephole optimizer (optimize.rs) fuses common instruction sequences into superinstructions. These reduce interpreter dispatch overhead by combining multiple logical operations into one internal instruction.
Examples include:
- Fused binops:
BinOpLocalLocal*,BinOpLocalConst*,BinOpStackGlobal*
Combine local/global access, a binary operation, and sometimes a store/tee. - Fused jumps:
JumpCmpLocalConst*,JumpCmpLocalLocal*,JumpCmpStackConst*
Combine comparison and conditional branch logic.
Linear memory is implemented through the LinearMemory trait. The backend is selected with engine::Config::with_memory_backend().
Available backends:
VecMemory- contiguousVec<u8>backing; the default backend.PagedMemory- chunk-based allocation, useful when growing memory without reallocating one large buffer.LazyLinearMemory- wraps another backend and allocates memory on first access.- Custom backends through
MemoryBackend::custom().
TinyWasm's interpreter is intentionally simple today: validated WebAssembly is lowered to internal instructions, optimized with peephole fusion, and executed by an iterative dispatch loop.
Future work may explore additional dispatch and code-generation strategies, including Rust's experimental loop_match state-machine work, explicit tail calls, more aggressive superinstruction fusion, top-of-stack register allocation, or even optional JIT compilation.
- visit.rs - WebAssembly binary visitor
- optimize.rs - peephole optimizer and superinstruction fusion
- parallel.rs - multithreaded function parsing
- instructions.rs - internal instruction set
- value_stack.rs - typed value stacks
- call_stack.rs - call frame stack
- memory/mod.rs - memory backend trait and implementations