Skip to content

Latest commit

 

History

History
62 lines (42 loc) · 3.44 KB

File metadata and controls

62 lines (42 loc) · 3.44 KB

TinyWasm Architecture

TinyWasm follows the general runtime model described in the WebAssembly specification, but lowers validated WebAssembly into a compact internal instruction format before execution.

Runtime Layout

  • Values are stored in untyped stacks:
    • stack_32 for i32, f32, funcref, and externref
    • stack_64 for i64 and f64
    • stack_128 for v128
  • Locals are stored directly in the value stacks. Each CallFrame stores a locals_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 as Jump, JumpIfZero, BranchTable*, DropKeep*, and Return.
  • Execution is a single iterative interpreter loop over the lowered instruction stream.

Internal Bytecode

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 .twasm for reuse

Optimizer

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.

Memory Backends

Linear memory is implemented through the LinearMemory trait. The backend is selected with engine::Config::with_memory_backend().

Available backends:

  • VecMemory - contiguous Vec<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().

Future Experiments

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.

Code Map