Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit 51d0c63

Browse files
docs: architecture
Signed-off-by: Henry Gressmann <[email protected]>
1 parent f26a0ca commit 51d0c63

File tree

4 files changed

+44
-4
lines changed

4 files changed

+44
-4
lines changed

ARCHITECTURE.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,27 @@
11
# TinyWasm's Architecture
2+
3+
TinyWasm follows the general Runtime Structure described in the [WebAssembly Specification](https://webassembly.github.io/spec/core/exec/runtime.html).
4+
Some key differences are:
5+
6+
- Values are stored without their type, (as `u64`), and the type is inferred from the instruction that uses them. This is possible because the instructions are validated before execution and the type of each value can be inferred from the instruction.
7+
- TinyWasm has a explicit stack for values, labels and frames. This is mostly for simplicity in the implementation, but also allows for some optimizations.
8+
- Floats always use a canonical NaN representation, the spec allows for multiple NaN representations.
9+
- TinyWasm uses a custom bytecode format (see [Bytecode Format](#bytecode-format) for more details)
10+
- Global state in the `Store` can be addressed from module instances other than the owning module. This is to allow more efficient access to imports and exports. Ownership is still enforced implicitly by requiring a reference to the instance to access it which can not be changed using the WebAssembly instructions.
11+
- The `Store` is not thread-safe. This is to allow for more efficient access to the `Store` and its contents. When later adding support for threads, a `Mutex` can be used to make it thread-safe but the overhead of requiring a lock for every access is not necessary for single-threaded applications.
12+
- TinyWasm is architectured to allow for a JIT compiler to be added later. Functions are stored as FunctionInstances which can contain either a `WasmFunction` or a `HostFunction`. A third variant `JitFunction` could be added later to store a pointer to the compiled function. This would allow for the JIT to be used transparently without changing the rest of the runtime.
13+
- TinyWasm is designed to be used in `no_std` environments. The `std` feature is enabled by default, but can be disabled to remove the dependency on `std` and `std::io`. This is done by disabling the `std` and `parser` features. The `logging` feature can also be disabled to remove the dependency on `log`. This is not recommended, since `libm` is not as performant as the compiler's math intrinsics, especially on wasm32 targets, but can be useful for resource-constrained devices or other environments where `std` is not available such as OS kernels.
14+
- Call Frames are executed in a loop instead of recursively. This allows the use of a single stack for all frames and makes it easier to pause execution and resume it later, or to step through the code one instruction at a time.
15+
16+
## Bytecode Format
17+
18+
To improve performance and reduce code size, instructions are encoded as enum variants instead of opcodes.
19+
This allows preprocessing the bytecode into a more compact 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.
20+
21+
Some instructions are split into multiple variants to reduce the size of the enum (e.g. `br_table` and `br_label`).
22+
Additionally, label instructions contain offsets relative to the current instruction to make branching faster and easier to implement.
23+
Also, `End` instructions are split into `End` and `EndBlock`.
24+
25+
See [instructions.rs](./crates/types/src/instructions.rs) for the full list of instructions.
26+
27+
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).

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<h1>TinyWasm</h1>
66
A tiny WebAssembly Runtime written in Rust
77
</div>
8-
8+
99
<br>
1010

1111
[![docs.rs](https://img.shields.io/docsrs/tinywasm?logo=rust)](https://docs.rs/tinywasm) [![Crates.io](https://img.shields.io/crates/v/tinywasm.svg?logo=rust)](https://crates.io/crates/tinywasm) [![Crates.io](https://img.shields.io/crates/l/tinywasm.svg)](./LICENSE-APACHE)
@@ -18,7 +18,6 @@ Some APIs to interact with the runtime are not yet exposed, and the existing one
1818
Results of the tests can be found [here](https://github.com/explodingcamera/tinywasm/tree/main/crates/tinywasm/tests/generated).
1919

2020
TinyWasm is not designed for performance, but rather for size and portability. However, it is still reasonably fast.
21-
There are a couple of low-hanging fruits on the performance side, but they are not a priority at the moment.
2221

2322
## Supported Proposals
2423

@@ -55,9 +54,11 @@ $ cargo add tinywasm
5554
Enables logging using the `log` crate. This is enabled by default.
5655
- **`parser`**\
5756
Enables the `tinywasm-parser` crate. This is enabled by default.
57+
- **`unsafe`**\
58+
Uses `unsafe` code to improve performance, particularly in Memory access
5859

5960
With all these features disabled, TinyWasm only depends on `core`, `alloc` and `libm` and can be used in `no_std` environments.
60-
Since `libm` is not as performant as the compiler's built-in math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)).
61+
Since `libm` is not as performant as the compiler's math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)), especially on wasm32 targets.
6162

6263
## Performance
6364

benches/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Benchmark results
2+
3+
Coming soon.
4+
5+
# Benchmarking
6+
7+
Benchmarks are run using [Criterion.rs](https://github.com/bheisler/criterion.rs) and can be found in the `benches` directory.
8+
9+
## Running benchmarks
10+
11+
```sh
12+
$ cargo bench --bench <name>
13+
```

crates/types/src/instructions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub enum ConstInstruction {
4343
/// * `br_table` stores the jump lables in the following `br_label` instructions to keep this enum small.
4444
/// * Lables/Blocks: we store the label end offset in the instruction itself and
4545
/// have seperate EndBlockFrame and EndFunc instructions to mark the end of a block or function.
46-
/// This makes it easier to implement the label stack (we call it BlockFrameStack) iteratively.
46+
/// This makes it easier to implement the label stack iteratively.
4747
///
4848
/// See <https://webassembly.github.io/spec/core/binary/instructions.html>
4949
#[derive(Debug, Clone, Copy)]

0 commit comments

Comments
 (0)