summaryrefslogtreecommitdiff
path: root/ARCHITECTURE.md
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-04-26 17:55:48 +0200
committerHenry <mail@henrygressmann.de>2026-04-26 17:55:48 +0200
commit27004a8738c7a3c32ac4fb6966f32647b4c96db7 (patch)
treebc3d663d1dc246df20ed30b1ecd0c19935c0f8bb /ARCHITECTURE.md
parent40bd20bb77b611f7974036c9f2b152a16a46c32a (diff)
docs: rework documentation, prepare pre-release
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'ARCHITECTURE.md')
-rw-r--r--ARCHITECTURE.md71
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