diff options
Diffstat (limited to 'ARCHITECTURE.md')
| -rw-r--r-- | ARCHITECTURE.md | 32 |
1 files changed, 14 insertions, 18 deletions
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 7aaa99c..2890089 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,27 +1,23 @@ # TinyWasm's Architecture TinyWasm follows the general Runtime Structure described in the [WebAssembly Specification](https://webassembly.github.io/spec/core/exec/runtime.html). -Some key differences are: -- **Type Storage**: Types are inferred from usage context rather than stored explicitly, with all values held as `u64`. -- **Stack Design**: Implements a specific stack for values, labels, and frames to simplify the implementation and enable optimizations. -- **Bytecode Format**: Adopts a custom bytecode format to reduce memory usage and improve performance by allowing direct execution without the need for decoding. -- **Global State Access**: Allows cross-module access to the `Store`'s global state, optimizing imports and exports access. Access requires a module instance reference, maintaining implicit ownership through a reference count. -- **Non-thread-safe Store**: Designed for efficiency in single-threaded applications. -- **JIT Compilation Support**: Prepares for JIT compiler integration with function instances designed to accommodate `WasmFunction`, `HostFunction`, or future `JitFunction`. -- **`no_std` Environment Support**: Offers compatibility with `no_std` environments by allowing disabling of `std` feature -- **Call Frame Execution**: Executes call frames in a single loop rather than recursively, using a single stack for all frames, facilitating easier pause, resume, and step-through. +Key runtime layout: -## Bytecode Format +- Values are stored in four fixed-capacity typed stacks: `stack_32` (`i32`/`f32`), `stack_64` (`i64`/`f64`), `stack_128` (`v128`), and `stack_ref` (`funcref`/`externref`). +- 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. -To improve performance and reduce code size, instructions are encoded as enum variants instead of opcodes. -This allows preprocessing the bytecode into a more memory aligned format, which can be loaded directly into memory and executed without decoding later. This can skip the decoding step entirely on resource-constrained devices where memory is limited. See this [blog post](https://wasmer.io/posts/improving-with-zero-copy-deserialization) by Wasmer -for more details which inspired this design. +## Precompiled Modules -Some instructions are split into multiple variants to reduce the size of the enum (e.g. `br_table` and `br_label`). -Additionally, label instructions contain offsets relative to the current instruction to make branching faster and easier to implement. -Also, `End` instructions are split into `End` and `EndBlock`. Others are also combined, especially in cases where the stack can be skipped. +`TinyWasmModule` 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. -See [instructions.rs](./crates/types/src/instructions.rs) for the full list of instructions. +See: -This is a area that can still be improved. While being able to load pre-processes bytecode directly into memory is nice, in-place decoding could achieve similar speeds, see [A fast in-place interpreter for WebAssembly](https://arxiv.org/abs/2205.01183). +- [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) |
