diff options
Diffstat (limited to 'ARCHITECTURE.md')
| -rw-r--r-- | ARCHITECTURE.md | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c5a5a0e..422dbb5 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,23 +1,62 @@ -# TinyWasm's Architecture +# TinyWasm Architecture -TinyWasm follows the general Runtime Structure described in the [WebAssembly Specification](https://webassembly.github.io/spec/core/exec/runtime.html). +TinyWasm follows the general runtime model described in the [WebAssembly specification](https://webassembly.github.io/spec/core/exec/runtime.html), but lowers validated WebAssembly into a compact internal instruction format before execution. -Key runtime layout: +## Runtime Layout -- Values are stored in four fixed-capacity typed stacks: `stack_32` (`i32`/`f32`/`funcref`/`externref`), `stack_64` (`i64`/`f64`), `stack_128` (`v128`) -- Locals are allocated in those value stacks. Each `CallFrame` stores `locals_base`, and local ops index from that base. -- Calls use a separate fixed-capacity `CallStack` of `CallFrame`s. -- Structured control (`block`/`loop`/`if`/`br*`) is lowered during parsing to jump-oriented instructions: `Jump`, `JumpIfZero`, `BranchTable*`, `DropKeep*`, and `Return`. -- The interpreter executes this lowered bytecode in a single iterative loop. +- 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. -## Precompiled Modules +## Internal Bytecode -Modules can be serialized to `.twasm` (`serialize_twasm`) and loaded later (`from_twasm`). -This allows deployments that execute precompiled modules without enabling the parser in the runtime binary. +TinyWasm does not interpret WebAssembly instructions directly. During parsing and validation, WebAssembly is translated into TinyWasm's internal bytecode format. -See: +This internal representation is designed to make execution simpler and cheaper: -- [visit.rs](./crates/parser/src/visit.rs) -- [instructions.rs](./crates/types/src/instructions.rs) -- [value_stack.rs](./crates/tinywasm/src/interpreter/stack/value_stack.rs) -- [call_stack.rs](./crates/tinywasm/src/interpreter/stack/call_stack.rs) +- 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 + +- [visit.rs](./crates/parser/src/visit.rs) - WebAssembly binary visitor +- [optimize.rs](./crates/parser/src/optimize.rs) - peephole optimizer and superinstruction fusion +- [parallel.rs](./crates/parser/src/parallel.rs) - multithreaded function parsing +- [instructions.rs](./crates/types/src/instructions.rs) - internal instruction set +- [value_stack.rs](./crates/tinywasm/src/interpreter/stack/value_stack.rs) - typed value stacks +- [call_stack.rs](./crates/tinywasm/src/interpreter/stack/call_stack.rs) - call frame stack +- [memory/mod.rs](./crates/tinywasm/src/store/memory/mod.rs) - memory backend trait and implementations |
