diff --git a/CLAUDE.md b/CLAUDE.md index c134902..87504aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,28 +16,34 @@ The pipeline: **WebAssembly → Rust source → Safe binary** ## Repository structure -The project is a Rust workspace with three crates: +The project is a Rust workspace with four crates: | Crate | Purpose | `no_std` | |-------|---------|----------| -| `crates/herkos/` | CLI transpiler: parses `.wasm` binaries, emits Rust source code | No (`std`) | +| `crates/herkos-core/` | Core transpiler library: parses `.wasm`, builds IR, optimizes, emits Rust | No (`std`) | +| `crates/herkos/` | CLI wrapper around `herkos-core` | No (`std`) | | `crates/herkos-runtime/` | Runtime library shipped with transpiled output | **Yes** | | `crates/herkos-tests/` | Integration tests + benchmarks: WAT/C/Rust → .wasm → transpile → test | No (`std`) | -### Transpiler pipeline (`crates/herkos/src/`) +### Transpiler pipeline (`crates/herkos-core/src/`) ``` -.wasm → parser/ → ir/builder/ → optimizer/ → backend/safe.rs → codegen/ → rustfmt - (wasmparser) (SSA IR) (dead blocks) (SafeBackend) (Rust source) +.wasm → parser/ → ir/builder/ → optimize_ir() → lower_phis() → optimize_lowered_ir() → codegen/ → rustfmt + (wasmparser) (SSA IR) (pre-lowering) (SSA destruct) (post-lowering) (Rust source) ``` Key modules: - `parser/` — Wasm binary parsing via `wasmparser` crate -- `ir/` — SSA-form intermediate representation (`ModuleInfo`, `IrFunction`, `IrBlock`, `IrInstr`) +- `ir/` — SSA-form intermediate representation + - `ir/types.rs` — `ModuleInfo`, `IrFunction`, `IrBlock`, `IrInstr`, `VarId`, `DefVar`, `UseVar`, `BlockId`, etc. - `ir/builder/` — Wasm → IR translation (core.rs, translate.rs, assembly.rs, analysis.rs) -- `optimizer/` — IR optimization passes (currently: dead block elimination) + - `ir/lower_phis.rs` — SSA destruction: phi nodes → predecessor `Assign` instructions +- `optimizer/` — IR optimization passes, split into two phases: + - **Pre-lowering** (on SSA IR with phi nodes): `dead_blocks`, `const_prop`, `algebraic`, `copy_prop` + - **Post-lowering** (on phi-free IR): `empty_blocks`, `dead_blocks`, `merge_blocks`, `copy_prop`, `local_cse`, `gvn`, `dead_instrs`, `branch_fold`, `licm` - `backend/` — Backend trait + `SafeBackend` (bounds-checked, no unsafe) -- `codegen/` — IR → Rust source (module.rs, function.rs, instruction.rs, traits.rs, export.rs, constructor.rs) +- `codegen/` — IR → Rust source (module.rs, function.rs, instruction.rs, traits.rs, export.rs, constructor.rs, env.rs, types.rs, utils.rs) +- `c_ffi.rs` — C-compatible FFI wrapper around `transpile()` ### Runtime (`crates/herkos-runtime/src/`) @@ -58,7 +64,6 @@ Key modules: ```bash cargo build # build all crates -cargo test # run all tests cargo clippy --all-targets # lint (CI enforced) cargo fmt --check # format check (CI enforced) cargo bench -p herkos-tests # benchmarks @@ -66,16 +71,41 @@ cargo bench -p herkos-tests # benchmarks Run a single crate's tests: ```bash -cargo test -p herkos +cargo test -p herkos-core # transpiler unit tests (IR, optimizer, codegen) cargo test -p herkos-runtime cargo test -p herkos-tests ``` +**`herkos-tests` must always be run twice** — once with optimizations off, once on — to verify that the optimizer does not change observable behavior: + +```bash +HERKOS_OPTIMIZE=0 cargo test -p herkos-tests # unoptimized output +HERKOS_OPTIMIZE=1 cargo test -p herkos-tests # optimized output +``` + +`HERKOS_OPTIMIZE` is consumed by `herkos-tests/build.rs` at compile time to control whether the transpiled test modules are generated with `-O` or not. It has no effect on `herkos-core`, `herkos-runtime`, or production code. CI enforces both runs. For all other crates, `cargo test` without this variable is sufficient. + CLI usage: ```bash -cargo run -p herkos -- input.wasm --output output.rs +cargo run -p herkos -- input.wasm --output output.rs # transpile +cargo run -p herkos -- input.wasm -O --output output.rs # with optimizations +``` + +### Sphinx documentation + +The `docs/` directory is a Sphinx project using [MyST](https://myst-parser.readthedocs.io/) (Markdown) and [sphinx-needs](https://sphinx-needs.readthedocs.io/) (traceability directives). Build with: + +```bash +cd docs +python -m venv .venv && source .venv/bin/activate # first time only +pip install -r requirements.txt # first time only + +make html # generate auto-files then build HTML → _build/html/index.html +make clean # remove build artifacts ``` +`make html` runs `python scripts/generate_all.py` first (auto-generates need files), then calls `sphinx-build`. + ## Key architectural concepts ### Memory model @@ -113,15 +143,23 @@ See SPECIFICATION.md §4.5. - `WasmResult = Result` — no panics, no unwinding - `ConstructionError` for programming errors during module instantiation +### SSA IR and phi lowering + +The IR is pure SSA: every variable is defined exactly once (`DefVar` token, non-`Copy`; enforced at build time). Phi nodes at join points are lowered to predecessor `Assign` instructions before codegen by `lower_phis::lower()`, which returns a `LoweredModuleInfo` newtype that statically guarantees no phi nodes remain. Optimization runs in two phases: **pre-lowering** (on SSA IR with phi nodes) and **post-lowering** (on `LoweredModuleInfo`). + +### Env context pattern + +Functions that call imports or read/write mutable globals receive an `Env<'_, H>` parameter bundling `host: &mut H` and `globals: &mut Globals`. This avoids threading host + globals as separate parameters throughout every function signature. + ### Current status -- **Implemented**: Safe backend only (runtime bounds checking, no unsafe in output) -- **Not yet implemented**: Verified backend, hybrid backend, `--max-pages` CLI effect, WASI traits +- **Implemented**: Safe backend only (runtime bounds checking, no unsafe in output), full optimizer pipeline, C FFI +- **Not yet implemented**: Verified backend, hybrid backend, `--max-pages` CLI flag, WASI traits - See `docs/FUTURE.md` for planned features ## `no_std` constraint -`herkos-runtime` and all transpiled output **must be `#![no_std]`**. No heap allocation without the optional `alloc` feature gate. No panics, no `format!`, no `String`. Errors are `Result` only. The `herkos` CLI crate is a standard `std` binary. +`herkos-runtime` and all transpiled output **must be `#![no_std]`**. No heap allocation without the optional `alloc` feature gate. No panics, no `format!`, no `String`. Errors are `Result` only. The `herkos` CLI and `herkos-core` crates are standard `std` binaries/libraries. ## Coding conventions diff --git a/README.md b/README.md index a61ba07..6fb1e73 100644 --- a/README.md +++ b/README.md @@ -151,8 +151,8 @@ cargo bench -p herkos-tests # benchmarks ## Documentation -- [Requirements](docs/REQUIREMENTS.md) — formal requirements (REQ_* IDs) -- [Specification](docs/SPECIFICATION.md) — architecture, transpilation rules, memory model, security analysis +- [Requirements](docs/REQUIREMENTS.rst) — formal requirements (REQ_* IDs) +- [Specification](docs/SPECIFICATION.rst) — architecture, transpilation rules, memory model, security analysis - [Future work](docs/FUTURE.md) — verified backend, hybrid backend, temporal isolation ## License diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..4a1b405 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_gen/ diff --git a/docs/FUTURE.md b/docs/FUTURE.md index 934c8bf..2f74775 100644 --- a/docs/FUTURE.md +++ b/docs/FUTURE.md @@ -1,6 +1,6 @@ # Future Extensions -This document describes features that are **planned but not yet implemented**. For the current specification, see [SPECIFICATION.md](SPECIFICATION.md). +This document describes features that are **planned but not yet implemented**. For the current specification, see [Specification](specification/index.rst). --- @@ -183,4 +183,4 @@ fn load_i32_verified(memory: &IsolatedMemory, offset: u32) -> i32 { - **Automated refactoring suggestions** for better Rust idioms in generated code - **DWARF debug info preservation** for source-level debugging of transpiled code - **Proof coverage reports**: per-function and per-module percentage of accesses that are proven vs. runtime-checked -- **Dynamic linking** of transpiled modules (open question — see [SPECIFICATION.md §8](SPECIFICATION.md#8-open-questions)) +- **Dynamic linking** of transpiled modules (open question — see {ref}`SPECIFICATION §7 `) diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..7add40d --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,164 @@ +# Getting Started + +## Installation + +From crates.io: +```bash +cargo install herkos +``` + +From source: +```bash +git clone https://github.com/arnoox/herkos.git +cd herkos +cargo install --path crates/herkos +``` + +## Basic Usage + +```bash +herkos input.wasm --output output.rs +herkos input.wasm -O --output output.rs # with IR optimizations enabled +``` + +| Option | Description | Required | +|--------|-------------|----------| +| `input.wasm` | Path to WebAssembly module | Yes | +| `--output`, `-o` | Output Rust file path (defaults to stdout) | No | +| `--optimize`, `-O` | Enable IR optimization passes | No | + +## Understanding the Output + +The transpiler produces a self-contained Rust source file that depends only on `herkos-runtime`. The output contains: + +```rust +// Generated output.rs +use herkos_runtime::*; + +struct Globals { ... } // ← mutable globals +const G1: i64 = 42; // ← immutable + +fn func_0(...) { ... } // ← Wasm functions +fn func_1(...) { ... } + +struct Module { + memory: IsolatedMemory, + globals: Globals, + table: Table, +} + +impl Module { ... } // ← exports as methods +trait ModuleImports { ... } // ← required capabilities +``` + +## Using Transpiled Code + +### Direct inclusion + +```rust +use herkos_runtime::{IsolatedMemory, WasmResult}; + +include!("path/to/output.rs"); + +fn main() -> WasmResult<()> { + let mut module = Module::<256, 4>::new( + 16, // initial pages + Globals::default(), // module globals + Table::default(), // call table + )?; + + let result = module.my_function(42)?; + println!("Result: {}", result); + Ok(()) +} +``` + +### Via build.rs (recommended for automated workflows) + +```rust +// build.rs +use std::env; +use std::path::PathBuf; + +fn main() { + let out_dir = env::var("OUT_DIR").unwrap(); + let out_path = PathBuf::from(&out_dir); + + println!("cargo:rerun-if-changed=wasm-modules/math.wasm"); + + let wasm_bytes = std::fs::read("wasm-modules/math.wasm").unwrap(); + let options = herkos::TranspileOptions::default(); + let rust_code = herkos::transpile(&wasm_bytes, &options).unwrap(); + std::fs::write(out_path.join("math_module.rs"), rust_code).unwrap(); +} +``` + +```rust +// src/main.rs +use herkos_runtime::WasmResult; +include!(concat!(env!("OUT_DIR"), "/math_module.rs")); + +fn main() -> WasmResult<()> { + let mut module = Module::<16, 0>::new(1, Globals::default(), Table::default())?; + let result = module.add(5, 3)?; + println!("Result: {}", result); + Ok(()) +} +``` + +When including multiple modules, wrap them in Rust modules to avoid name collisions: + +```rust +mod math { + include!(concat!(env!("OUT_DIR"), "/math_module.rs")); +} +mod crypto { + include!(concat!(env!("OUT_DIR"), "/crypto_module.rs")); +} +``` + +## Example: C to Rust via Wasm + +This example walks through the full pipeline: starting from a C source file, +compiling it to a Wasm binary, and then using `herkos` to transpile that binary +into safe Rust code you can call directly. + +Start with a simple C library: + +```c +// math.c +int add(int a, int b) { return a + b; } +int multiply(int a, int b) { return a * b; } +``` + +Compile it to Wasm using `clang` and `wasm-ld`, then transpile with `herkos`: + +```bash +clang --target=wasm32 -O2 -c math.c -o math.o +wasm-ld math.o -o math.wasm --no-entry +herkos math.wasm --output math.rs +``` + +`--no-entry` tells the linker not to require a `main` symbol, since this is a +library. The transpiler reads `math.wasm` and writes `math.rs`, a self-contained +Rust module that only depends on `herkos-runtime`. + +Include the generated file and instantiate the module to call its exports: + +```rust +use herkos_runtime::WasmResult; +include!("math.rs"); + +fn main() -> WasmResult<()> { + let mut module = Module::<16, 0>::new(1, Globals::default(), Table::default())?; + println!("2 + 3 = {}", module.add(2, 3)?); + println!("4 * 5 = {}", module.multiply(4, 5)?); + Ok(()) +} +``` + +The const generics `<16, 0>` set the memory limit to 16 pages (1 MiB) and the +indirect-call table size to 0, since this module makes no indirect calls. Each +exported function returns `WasmResult`, propagating any Wasm traps (such as +out-of-bounds memory access or integer overflow) as `Err(WasmTrap)` rather than +panicking. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..1cb60c7 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +.PHONY: help html generate clean + +help: + @echo " html build HTML documentation" + @echo " generate regenerate auto-generated need files" + @echo " clean remove build artifacts" + +generate: + python3 scripts/generate_all.py + +html: generate + $(SPHINXBUILD) -b html $(SOURCEDIR) $(BUILDDIR)/html + +clean: + rm -rf $(BUILDDIR) diff --git a/docs/REQUIREMENTS.md b/docs/REQUIREMENTS.md deleted file mode 100644 index 2be4664..0000000 --- a/docs/REQUIREMENTS.md +++ /dev/null @@ -1,364 +0,0 @@ -# Requirements - -## 1. Purpose - -This document defines **what** the herkos compilation pipeline shall achieve: its goals, constraints, and formal requirements. For **how** these are implemented, see [SPECIFICATION.md](SPECIFICATION.md). - -herkos is a compilation pipeline that transforms WebAssembly modules into memory-safe Rust code with compile-time isolation guarantees, replacing runtime hardware-based memory protection (MMU/MPU) with type-system-enforced safety. - -``` -┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ ┌─────────────┐ -│ C/C++ │ ───> │ WebAssembly │ ───> │ Rust Transpiler │ ───> │ Safe Rust │ -│ Source │ │ (Wasm) │ │ + Runtime │ │ Binary │ -└─────────────┘ └──────────────┘ └─────────────────┘ └─────────────┘ -``` - -## 2. Problem Statement - -Systems that mix components of different trust or criticality levels require **freedom from interference** — the guarantee that one module cannot corrupt the state of another. In practice this means: - -- A higher-criticality component shall not be corruptible by a lower-criticality one -- An untrusted third-party library shall be contained so it cannot reach outside its sandbox -- Modules at different trust levels shall have provable isolation boundaries - -This isolation is typically achieved through hardware mechanisms (MMU, MPU) or hypervisors. While effective, these approaches are: - -- **Expensive in performance**: context switches, TLB flushes, and memory barrier overhead -- **Expensive in energy**: critical for battery-powered and thermally constrained embedded systems -- **Complex to implement**: MPU region configuration, partition scheduling, and efficient inter-partition communication require significant engineering effort -- **Hard to certify**: the isolation argument depends on correct hardware configuration, OS behavior, and linker scripts — all of which shall be verified together - -herkos takes a different approach: **move the isolation guarantee from runtime hardware to compile-time type system enforcement**. If the Rust compiler accepts the transpiled code, isolation is guaranteed — no MMU, no context switches, no runtime overhead for proven accesses. - -> **Note on Hardware Isolation:** -> -> herkos does *not* claim that MPU/MMU isolation is obsolete. Hardware isolation remains essential for: -> - **Untrusted kernels and hypervisors** — compile-time safety assumes trusted compilation and runtime -> - **Defense in depth** — multiple isolation layers reduce risk from both compiler bugs and runtime exploits -> - **Legacy systems** — many existing codebases cannot be rewritten in Rust -> - **Dynamic code** — dynamically loaded code cannot benefit from static Rust type safety -> - **Cross-language systems** — mixed C/C++/Rust systems need runtime isolation -> -> herkos is positioned as a **complementary approach**: replace runtime isolation *where* compile-time safety is achievable, and use hardware isolation for the rest. - -## 3. Goals - -- Achieve memory safety and inter-module isolation guarantees at compile time rather than runtime -- Provide performance competitive with or better than hardware-based isolation -- Provide a migration path for existing C/C++ codebases toward provable isolation without full rewrites -- Enable capability-based security enforced through the type system (freedom from interference by construction) -- Support incremental adoption: start with the safe backend (runtime checks, no proofs needed), progressively move to verified as proof coverage improves - -## 4. Functional Requirements - -### 4.1 Memory Model - -```{req} Wasm Page-Based Memory Model -:id: REQ_MEM_PAGE_MODEL -:status: open -:tags: memory, wasm-spec -Linear memory shall be organized in pages of 64 KiB (per the WebAssembly specification). -Each module declares an initial page count and an optional maximum page count. The -memory.grow instruction adds pages at runtime up to the declared maximum. -``` - -```{req} Compile-Time Memory Sizing -:id: REQ_MEM_COMPILE_TIME_SIZE -:status: open -:tags: memory, no_std, static-sizing -The maximum memory size for each module shall be fixed at compile time. No heap -allocation is permitted for memory backing storage. All memory shall be statically -sized. -``` - -```{req} Bounds-Checked Memory Access -:id: REQ_MEM_BOUNDS_CHECKED -:status: open -:tags: memory, safety -All memory accesses in the safe backend shall be bounds-checked against the current -active memory size (active_pages * PAGE_SIZE). Out-of-bounds accesses shall return -an error (WasmTrap::OutOfBounds), never panic or invoke undefined behavior. -``` - -```{req} Memory Growth Without Allocation -:id: REQ_MEM_GROW_NO_ALLOC -:status: open -:tags: memory, memory.grow, no_std -memory.grow shall not perform heap allocation. New pages shall be zero-initialized -within pre-allocated storage. Returns previous page count on success, -1 on failure. -``` - -```{req} Bulk Memory Operations -:id: REQ_MEM_BULK_OPS -:status: open -:tags: memory, bulk-operations, wasm-spec -The transpiler shall support WebAssembly bulk memory operations: memory.fill, -memory.init, and data.drop. All operations shall be bounds-checked. Out-of-bounds -operations shall trap with WasmTrap::OutOfBounds, never panic. -``` - -```{req} Data Segment Support -:id: REQ_MEM_DATA_SEGMENTS -:status: open -:tags: memory, data-segments -Passive data segments shall be stored as compile-time constants in the generated -output. memory.init shall copy from these constants into the module's linear memory. -``` - -### 4.2 Module Representation - -```{req} Two Module Types -:id: REQ_MOD_TWO_TYPES -:status: open -:tags: modules, memory-ownership -The system shall support two module types: (1) modules that own their own memory -(process-like), and (2) modules that borrow memory from a caller (library-like). -This distinction is the primary mechanism for spatial isolation. -``` - -```{req} Globals as Typed Struct Fields -:id: REQ_MOD_GLOBALS -:status: open -:tags: modules, globals -Mutable Wasm globals shall have statically typed, per-instance storage. Immutable -globals shall be compile-time constants. Global access shall be resolved statically, -with no dynamic lookup. -``` - -```{req} Indirect Call Table -:id: REQ_MOD_TABLE -:status: open -:tags: modules, table, call_indirect -Each module shall have a table for indirect call dispatch. Table entries store -function references with type index and function index. Indirect calls shall -validate the type signature before dispatch. -``` - -### 4.3 Imports, Exports, and Capabilities - -```{req} Imports as Trait Bounds -:id: REQ_CAP_IMPORTS -:status: open -:tags: imports, traits, capabilities -Wasm module imports shall be statically checked capabilities. Related imports -shall be grouped into discrete capability sets. If a module does not import a -capability, no code path to invoke it shall exist. -``` - -```{req} Exports as Trait Implementations -:id: REQ_CAP_EXPORTS -:status: open -:tags: exports, traits -Wasm module exports shall be exposed as statically typed interfaces on the -transpiled module. This shall enable inter-module linking via interface composition. -``` - -```{req} Zero-Cost Dispatch -:id: REQ_CAP_ZERO_COST -:status: open -:tags: traits, dispatch, performance -Capability dispatch shall incur zero runtime overhead compared to direct function -calls. If a module does not import a capability, no code for that capability shall -be generated. -``` - -```{req} WASI Support via Standard Traits -:id: REQ_CAP_WASI -:status: open -:tags: wasi, imports, traits -WASI (WebAssembly System Interface) support shall be provided as a standard set -of capability interfaces shipped with the runtime. The host provides whichever -subset it supports. -``` - -### 4.4 Transpilation - -```{req} Wasm-to-Rust Function Translation -:id: REQ_TRANS_FUNCTIONS -:status: open -:tags: transpilation, functions -Each Wasm function shall be transpiled to a Rust function with explicit access to -module state (memory, globals, table) and granted capabilities. -``` - -```{req} Control Flow Mapping -:id: REQ_TRANS_CONTROL_FLOW -:status: open -:tags: transpilation, control-flow -Wasm control flow (block, loop, if, br, br_if, br_table) shall map to safe Rust -control flow structures. No goto or unsafe control flow. -``` - -```{req} Safe Indirect Call Dispatch -:id: REQ_TRANS_INDIRECT_CALLS -:status: open -:tags: transpilation, indirect-calls, safety -Indirect calls (call_indirect) shall be dispatched using only safe Rust — no -function pointers, no unsafe dispatch. The dispatch mechanism shall validate type -signatures and enumerate only functions matching the expected type. -``` - -```{req} Structural Type Equivalence -:id: REQ_TRANS_TYPE_EQUIVALENCE -:status: open -:tags: transpilation, types -Type checks in call_indirect shall use structural equivalence: two type indices -match if they have identical parameter and result types, regardless of index. -Type equivalence shall be resolved at transpile time. -``` - -```{req} Self-Contained Output -:id: REQ_TRANS_SELF_CONTAINED -:status: open -:tags: transpilation, output -Transpiled code shall be self-contained, depending only on herkos-runtime. Output -shall be formatted (rustfmt), readable, and auditable. No panics, no unwinding — -only Result for error handling. -``` - -```{req} Version Information in Generated Code -:id: REQ_TRANS_VERSION_INFO -:status: open -:tags: transpilation, output, metadata -Generated code shall include version information: the herkos transpiler version -and the WebAssembly binary format version. This enables traceability and debugging -of transpiled modules. -``` - -```{req} Deterministic Code Generation -:id: REQ_TRANS_DETERMINISTIC -:status: open -:tags: transpilation, determinism -Generated output shall be identical regardless of CPU, thread count, execution order, -or random seed. Enables reproducible builds and auditable output. -``` - -### 4.5 Error Handling - -```{req} Trap-Based Error Handling -:id: REQ_ERR_TRAPS -:status: open -:tags: error-handling, traps -Wasm traps shall be reported as typed, structured errors. The following trap -categories shall be distinguished: out-of-bounds memory access, division by zero, -integer overflow, unreachable code, indirect call type mismatch, table out-of-bounds, -and undefined table element. No exceptions, no panics, no unwinding. -``` - -### 4.6 Platform Constraints - -```{req} no_std Compatibility -:id: REQ_PLATFORM_NO_STD -:status: open -:tags: no_std, embedded -herkos-runtime and all transpiled output shall be #![no_std]. No heap allocation -without the optional alloc feature gate. No panics, no format!, no String in the -runtime or generated code. Enables resource-constrained and embedded targets. -``` - -## 5. Non-Functional Requirements - -### 5.1 Safety and Isolation - -```{req} Compile-Time Isolation Enforcement -:id: REQ_ISOLATION_COMPILE_TIME -:status: open -:tags: isolation, compile-time, safety -Isolation properties shall be verified at compile time via Rust's type system. -The safety argument shall not depend on correct hardware configuration, OS behavior, -or runtime state. If the Rust compiler accepts the transpiled code, isolation is -guaranteed. -``` - -```{req} Freedom from Interference -:id: REQ_FREEDOM_FROM_INTERFERENCE -:status: open -:tags: isolation, freedom-from-interference -No module shall be able to corrupt the state of another module. This property -— commonly known as "freedom from interference" — shall be enforced via spatial -isolation and capability enforcement. Note: herkos is not qualified to any -safety standard. It provides an isolation mechanism, not a certified safety case. -``` - -```{req} Spatial Isolation via Memory Ownership -:id: REQ_ISOLATION_SPATIAL -:status: open -:tags: isolation, memory, type-system -Each module shall operate on its own isolated memory. The type system shall -structurally prevent any cross-module memory access — there shall be no pointer, -offset, or API that allows one module to reach another module's linear memory. -``` - -```{req} Capability Enforcement via Traits -:id: REQ_ISOLATION_CAPABILITY -:status: open -:tags: isolation, capabilities -Capabilities shall be statically enforced at compile time. A module can only perform -operations that it was explicitly granted at instantiation. Missing capabilities -shall cause compile errors, not runtime failures. -``` - -### 5.2 Determinism - -```{req} Deterministic Execution Semantics -:id: REQ_DETERMINISM -:status: open -:tags: determinism, testing, debugging -Transpiled modules shall preserve WebAssembly's deterministic semantics. Each function -shall be pure with respect to its explicit state (parameters, globals, memory). Given -identical inputs, execution shall always produce identical outputs. Host imports are -the sole source of non-determinism and are isolated behind trait bounds. -``` - -This determinism enables: -- **Debugging**: Capture module state when a bug occurs, replay it locally -- **Testing**: Tests against concrete state snapshots — no flaky tests -- **Fuzzing**: Random inputs with confidence that crashes are reproducible -- **Record and replay**: Log function inputs in production, replay offline -- **Differential testing**: Compare transpiled output against a reference Wasm interpreter - -### 5.3 Performance - -```{req} Safe Backend Overhead -:id: REQ_PERF_SAFE_OVERHEAD -:status: open -:tags: performance, safe-backend -The safe backend (runtime bounds checking on every memory access) shall achieve -overhead of 15–30% compared to native execution. This is the baseline for all -modules. -``` - -```{req} Monomorphization Bloat Mitigation -:id: REQ_PERF_MONO_BLOAT -:status: open -:tags: performance, monomorphization, binary-size -The runtime and transpiler shall mitigate binary size explosion from generic code -specialization. Binary size shall be a tracked metric. -``` - -### 5.4 Security - -```{req} Threat Model — Protected Against -:id: REQ_SEC_PROTECTED -:status: open -:tags: security, threat-model -The system shall protect against: memory corruption (buffer overflows, use-after-free), -unauthorized resource access (files, network, system calls), cross-module interference, -and return-oriented programming (ROP) attacks. -``` - -```{req} Threat Model — Not Protected Against -:id: REQ_SEC_NOT_PROTECTED -:status: open -:tags: security, threat-model -The system does not protect against (current scope): logic bugs in the original source -code, side-channel attacks (timing, cache), resource exhaustion (infinite loops, memory -leaks within bounds), or timing interference. See FUTURE.md for temporal isolation plans. -``` - -## 6. Non-Goals - -- Complete automation of unsafe code to safe Rust transformation (some manual intervention may be required) -- 100% preservation of C/C++ performance characteristics -- Support for all possible C/C++ undefined behaviors -- Replacing formal safety cases — this tool provides evidence for isolation arguments, not a complete safety case diff --git a/docs/REQUIREMENTS.rst b/docs/REQUIREMENTS.rst new file mode 100644 index 0000000..d9dad40 --- /dev/null +++ b/docs/REQUIREMENTS.rst @@ -0,0 +1,411 @@ +Requirements +============ + +1. Purpose +---------- + +This document defines **what** the herkos compilation pipeline shall achieve: its goals, +constraints, and formal requirements. For **how** these are implemented, see +:doc:`specification/index`. + +herkos is a compilation pipeline that transforms WebAssembly modules into memory-safe Rust +code with compile-time isolation guarantees, replacing runtime hardware-based memory +protection (MMU/MPU) with type-system-enforced safety. + +.. mermaid:: + + flowchart TD + A["C/C++ Source"] --> B["WebAssembly (Wasm)"] + B --> C["Rust Transpiler + Runtime"] + C --> D["Safe Rust Binary"] + +2. Problem Statement +-------------------- + +Systems that mix components of different trust or criticality levels require **freedom from +interference** — the guarantee that one module cannot corrupt the state of another. In +practice this means: + +- A higher-criticality component shall not be corruptible by a lower-criticality one +- An untrusted third-party library shall be contained so it cannot reach outside its sandbox +- Modules at different trust levels shall have provable isolation boundaries + +This isolation is typically achieved through hardware mechanisms (MMU, MPU) or hypervisors. +While effective, these approaches are: + +- **Expensive in performance**: context switches, TLB flushes, and memory barrier overhead +- **Expensive in energy**: critical for battery-powered and thermally constrained embedded systems +- **Complex to implement**: MPU region configuration, partition scheduling, and efficient + inter-partition communication require significant engineering effort +- **Hard to certify**: the isolation argument depends on correct hardware configuration, OS + behavior, and linker scripts — all of which shall be verified together + +herkos takes a different approach: **move the isolation guarantee from runtime hardware to +compile-time type system enforcement**. If the Rust compiler accepts the transpiled code, +isolation is guaranteed — no MMU, no context switches, no runtime overhead for proven accesses. + +.. note:: + + **Note on Hardware Isolation:** + + herkos does *not* claim that MPU/MMU isolation is obsolete. Hardware isolation remains + essential for: + + - **Untrusted kernels and hypervisors** — compile-time safety assumes trusted compilation and runtime + - **Defense in depth** — multiple isolation layers reduce risk from both compiler bugs and runtime exploits + - **Legacy systems** — many existing codebases cannot be rewritten in Rust + - **Dynamic code** — dynamically loaded code cannot benefit from static Rust type safety + - **Cross-language systems** — mixed C/C++/Rust systems need runtime isolation + + herkos is positioned as a **complementary approach**: replace runtime isolation *where* + compile-time safety is achievable, and use hardware isolation for the rest. + +3. Goals +-------- + +- Achieve memory safety and inter-module isolation guarantees at compile time rather than runtime +- Provide performance competitive with or better than hardware-based isolation +- Provide a migration path for existing C/C++ codebases toward provable isolation without full rewrites +- Enable capability-based security enforced through the type system (freedom from interference by construction) +- Support incremental adoption: start with the safe backend (runtime checks, no proofs needed), + progressively move to verified as proof coverage improves + +4. Functional Requirements +-------------------------- + +4.1 Memory Model +~~~~~~~~~~~~~~~~ + +.. req:: Wasm Page-Based Memory Model + :id: REQ_MEM_PAGE_MODEL + :status: open + :tags: memory, wasm-spec + :links: WASM_MEMORY_TYPE, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + Linear memory shall be organized in pages of 64 KiB (per the WebAssembly specification). + Each module declares an initial page count and an optional maximum page count. The + ``memory.grow`` instruction adds pages at runtime up to the declared maximum. + +.. req:: Compile-Time Memory Sizing + :id: REQ_MEM_COMPILE_TIME_SIZE + :status: open + :tags: memory, no_std, static-sizing + + The maximum memory size for each module shall be fixed at compile time. No heap + allocation is permitted for memory backing storage. All memory shall be statically + sized. + +.. req:: Bounds-Checked Memory Access + :id: REQ_MEM_BOUNDS_CHECKED + :status: open + :tags: memory, safety + :links: WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_LOAD, WASM_I64_STORE, WASM_EXEC_MEMORY + + All memory accesses in the safe backend shall be bounds-checked against the current + active memory size (``active_pages * PAGE_SIZE``). Out-of-bounds accesses shall return + an error (``WasmTrap::OutOfBounds``), never panic or invoke undefined behavior. + +.. req:: Memory Growth Without Allocation + :id: REQ_MEM_GROW_NO_ALLOC + :status: open + :tags: memory, memory.grow, no_std + :links: WASM_MEMORY_GROW, WASM_MEMORY_SIZE + + ``memory.grow`` shall not perform heap allocation. New pages shall be zero-initialized + within pre-allocated storage. Returns previous page count on success, -1 on failure. + +.. req:: Bulk Memory Operations + :id: REQ_MEM_BULK_OPS + :status: open + :tags: memory, bulk-operations, wasm-spec + :links: WASM_EXEC_MEMORY + + The transpiler shall support WebAssembly bulk memory operations: ``memory.fill``, + ``memory.init``, and ``data.drop``. All operations shall be bounds-checked. + Out-of-bounds operations shall trap with ``WasmTrap::OutOfBounds``, never panic. + +.. req:: Data Segment Support + :id: REQ_MEM_DATA_SEGMENTS + :status: open + :tags: memory, data-segments + + Passive data segments shall be stored as compile-time constants in the generated + output. ``memory.init`` shall copy from these constants into the module's linear memory. + +4.2 Module Representation +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. req:: Two Module Types + :id: REQ_MOD_TWO_TYPES + :status: open + :tags: modules, memory-ownership + :links: WASM_MOD_MEMORIES, WASM_MOD_IMPORTS + + The system shall support two module types: (1) modules that own their own memory + (process-like), and (2) modules that borrow memory from a caller (library-like). + This distinction is the primary mechanism for spatial isolation. + +.. req:: Globals as Typed Struct Fields + :id: REQ_MOD_GLOBALS + :status: open + :tags: modules, globals + + Mutable Wasm globals shall have statically typed, per-instance storage. Immutable + globals shall be compile-time constants. Global access shall be resolved statically, + with no dynamic lookup. + +.. req:: Indirect Call Table + :id: REQ_MOD_TABLE + :status: open + :tags: modules, table, call_indirect + :links: WASM_TABLE_TYPE, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_CALL_INDIRECT + + Each module shall have a table for indirect call dispatch. Table entries store + function references with type index and function index. Indirect calls shall + validate the type signature before dispatch. + +4.3 Imports, Exports, and Capabilities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. req:: Imports as Trait Bounds + :id: REQ_CAP_IMPORTS + :status: open + :tags: imports, traits, capabilities + :links: WASM_MOD_IMPORTS, WASM_EXTERNAL_TYPE + + Wasm module imports shall be statically checked capabilities. Related imports + shall be grouped into discrete capability sets. If a module does not import a + capability, no code path to invoke it shall exist. + +.. req:: Exports as Trait Implementations + :id: REQ_CAP_EXPORTS + :status: open + :tags: exports, traits + :links: WASM_MOD_EXPORTS, WASM_EXTERNAL_TYPE + + Wasm module exports shall be exposed as statically typed interfaces on the + transpiled module. This shall enable inter-module linking via interface composition. + +.. req:: Zero-Cost Dispatch + :id: REQ_CAP_ZERO_COST + :status: open + :tags: traits, dispatch, performance + + Capability dispatch shall incur zero runtime overhead compared to direct function + calls. If a module does not import a capability, no code for that capability shall + be generated. + +.. req:: WASI Support via Standard Traits + :id: REQ_CAP_WASI + :status: open + :tags: wasi, imports, traits + + WASI (WebAssembly System Interface) support shall be provided as a standard set + of capability interfaces shipped with the runtime. The host provides whichever + subset it supports. + +4.4 Transpilation +~~~~~~~~~~~~~~~~~ + +.. req:: Wasm-to-Rust Function Translation + :id: REQ_TRANS_FUNCTIONS + :status: open + :tags: transpilation, functions + :links: WASM_MOD_FUNCTIONS, WASM_FUNC_TYPE + + Each Wasm function shall be transpiled to a Rust function with explicit access to + module state (memory, globals, table) and granted capabilities. + +.. req:: Control Flow Mapping + :id: REQ_TRANS_CONTROL_FLOW + :status: open + :tags: transpilation, control-flow + :links: WASM_BLOCK, WASM_LOOP, WASM_IF, WASM_BR, WASM_BR_IF, WASM_BR_TABLE, WASM_EXEC_CONTROL + + Wasm control flow (``block``, ``loop``, ``if``, ``br``, ``br_if``, ``br_table``) shall map + to safe Rust control flow structures. No goto or unsafe control flow. + +.. req:: Safe Indirect Call Dispatch + :id: REQ_TRANS_INDIRECT_CALLS + :status: open + :tags: transpilation, indirect-calls, safety + :links: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_EXEC_CALLS + + Indirect calls (``call_indirect``) shall be dispatched using only safe Rust — no + function pointers, no unsafe dispatch. The dispatch mechanism shall validate type + signatures and enumerate only functions matching the expected type. + +.. req:: Structural Type Equivalence + :id: REQ_TRANS_TYPE_EQUIVALENCE + :status: open + :tags: transpilation, types + + Type checks in ``call_indirect`` shall use structural equivalence: two type indices + match if they have identical parameter and result types, regardless of index. + Type equivalence shall be resolved at transpile time. + +.. req:: Self-Contained Output + :id: REQ_TRANS_SELF_CONTAINED + :status: open + :tags: transpilation, output + + Transpiled code shall be self-contained, depending only on ``herkos-runtime``. Output + shall be formatted (rustfmt), readable, and auditable. No panics, no unwinding — + only ``Result`` for error handling. + +.. req:: Version Information in Generated Code + :id: REQ_TRANS_VERSION_INFO + :status: open + :tags: transpilation, output, metadata + + Generated code shall include version information: the herkos transpiler version + and the WebAssembly binary format version. This enables traceability and debugging + of transpiled modules. + +.. req:: Deterministic Code Generation + :id: REQ_TRANS_DETERMINISTIC + :status: open + :tags: transpilation, determinism + + Generated output shall be identical regardless of CPU, thread count, execution order, + or random seed. Enables reproducible builds and auditable output. + +4.5 Error Handling +~~~~~~~~~~~~~~~~~~ + +.. req:: Trap-Based Error Handling + :id: REQ_ERR_TRAPS + :status: open + :tags: error-handling, traps + :links: WASM_UNREACHABLE + + Wasm traps shall be reported as typed, structured errors. The following trap + categories shall be distinguished: out-of-bounds memory access, division by zero, + integer overflow, unreachable code, indirect call type mismatch, table out-of-bounds, + and undefined table element. No exceptions, no panics, no unwinding. + +4.6 Platform Constraints +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. req:: no_std Compatibility + :id: REQ_PLATFORM_NO_STD + :status: open + :tags: no_std, embedded + + ``herkos-runtime`` and all transpiled output shall be ``#![no_std]``. No heap allocation + without the optional ``alloc`` feature gate. No panics, no ``format!``, no ``String`` in + the runtime or generated code. Enables resource-constrained and embedded targets. + +5. Non-Functional Requirements +------------------------------ + +5.1 Safety and Isolation +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. req:: Compile-Time Isolation Enforcement + :id: REQ_ISOLATION_COMPILE_TIME + :status: open + :tags: isolation, compile-time, safety + + Isolation properties shall be verified at compile time via Rust's type system. + The safety argument shall not depend on correct hardware configuration, OS behavior, + or runtime state. If the Rust compiler accepts the transpiled code, isolation is + guaranteed. + +.. req:: Freedom from Interference + :id: REQ_FREEDOM_FROM_INTERFERENCE + :status: open + :tags: isolation, freedom-from-interference + + No module shall be able to corrupt the state of another module. This property + — commonly known as "freedom from interference" — shall be enforced via spatial + isolation and capability enforcement. Note: herkos is not qualified to any + safety standard. It provides an isolation mechanism, not a certified safety case. + +.. req:: Spatial Isolation via Memory Ownership + :id: REQ_ISOLATION_SPATIAL + :status: open + :tags: isolation, memory, type-system + + Each module shall operate on its own isolated memory. The type system shall + structurally prevent any cross-module memory access — there shall be no pointer, + offset, or API that allows one module to reach another module's linear memory. + +.. req:: Capability Enforcement via Traits + :id: REQ_ISOLATION_CAPABILITY + :status: open + :tags: isolation, capabilities + + Capabilities shall be statically enforced at compile time. A module can only perform + operations that it was explicitly granted at instantiation. Missing capabilities + shall cause compile errors, not runtime failures. + +5.2 Determinism +~~~~~~~~~~~~~~~ + +.. req:: Deterministic Execution Semantics + :id: REQ_DETERMINISM + :status: open + :tags: determinism, testing, debugging + + Transpiled modules shall preserve WebAssembly's deterministic semantics. Each function + shall be pure with respect to its explicit state (parameters, globals, memory). Given + identical inputs, execution shall always produce identical outputs. Host imports are + the sole source of non-determinism and are isolated behind trait bounds. + +This determinism enables: + +- **Debugging**: Capture module state when a bug occurs, replay it locally +- **Testing**: Tests against concrete state snapshots — no flaky tests +- **Fuzzing**: Random inputs with confidence that crashes are reproducible +- **Record and replay**: Log function inputs in production, replay offline +- **Differential testing**: Compare transpiled output against a reference Wasm interpreter + +5.3 Performance +~~~~~~~~~~~~~~~ + +.. req:: Safe Backend Overhead + :id: REQ_PERF_SAFE_OVERHEAD + :status: open + :tags: performance, safe-backend + + The safe backend (runtime bounds checking on every memory access) shall achieve + overhead of 15–30% compared to native execution. This is the baseline for all + modules. + +.. req:: Monomorphization Bloat Mitigation + :id: REQ_PERF_MONO_BLOAT + :status: open + :tags: performance, monomorphization, binary-size + + The runtime and transpiler shall mitigate binary size explosion from generic code + specialization. Binary size shall be a tracked metric. + +5.4 Security +~~~~~~~~~~~~ + +.. req:: Threat Model — Protected Against + :id: REQ_SEC_PROTECTED + :status: open + :tags: security, threat-model + + The system shall protect against: memory corruption (buffer overflows, use-after-free), + unauthorized resource access (files, network, system calls), cross-module interference, + and return-oriented programming (ROP) attacks. + +.. req:: Threat Model — Not Protected Against + :id: REQ_SEC_NOT_PROTECTED + :status: open + :tags: security, threat-model + + The system does not protect against (current scope): logic bugs in the original source + code, side-channel attacks (timing, cache), resource exhaustion (infinite loops, memory + leaks within bounds), or timing interference. See ``FUTURE.rst`` for temporal isolation plans. + +6. Non-Goals +------------ + +- Complete automation of unsafe code to safe Rust transformation (some manual intervention may be required) +- 100% preservation of C/C++ performance characteristics +- Support for all possible C/C++ undefined behaviors +- Replacing formal safety cases — this tool provides evidence for isolation arguments, not a complete safety case diff --git a/docs/SPECIFICATION.md b/docs/SPECIFICATION.md deleted file mode 100644 index 6698e7b..0000000 --- a/docs/SPECIFICATION.md +++ /dev/null @@ -1,1101 +0,0 @@ -# Specification - -This document specifies the design and behavior of the herkos transpilation pipeline. It takes the goals and constraints defined in [REQUIREMENTS.md](REQUIREMENTS.md) as input and describes **how** they are achieved. - -Where the requirements say *what* the system must do, this specification says *how* it does it. - -For features that are planned but not yet implemented (verified/hybrid backends, temporal isolation, etc.), see [FUTURE.md](FUTURE.md). - -**Document Status**: Draft — Version 0.2 — 2026-03-16 - ---- - -## Table of Contents - -1. [Getting Started](#1-getting-started) -2. [Module Representation](#2-module-representation) -3. [Architecture](#3-architecture) -4. [Transpilation Rules](#4-transpilation-rules) -5. [Integration](#5-integration) -6. [Performance](#6-performance) -7. [Security Properties](#7-security-properties) -8. [Open Questions](#8-open-questions) -9. [References](#9-references) - ---- - -## 1. Getting Started - -### 1.1 Installation - -> Note: it is currently only possible to build from source. - -```bash -git clone https://github.com/anthropics/herkos.git -cd herkos -cargo install --path crates/herkos -``` - -### 1.2 Basic Usage - -```bash -herkos input.wasm --mode safe --output output.rs -``` - -| Option | Description | Required | -|--------|-------------|----------| -| `input.wasm` | Path to WebAssembly module | Yes | -| `--mode` | Code generation mode (currently only `safe` is implemented) | No | -| `--output` | Output Rust file path | No | -| `--max-pages` | Maximum memory pages when module declares no maximum | No | - -**Environment variables:** - -| Variable | Values | Default | Effect | -|----------|--------|---------|--------| -| `HERKOS_OPTIMIZE` | `1` or any other value | Unset (disabled) | When `HERKOS_OPTIMIZE=1`, enables IR optimization passes (currently dead block elimination). Set during transpilation, affects generated code size and performance. | - -> **Current limitations**: Only the `safe` backend is implemented. The `--mode` flag accepts `safe`, `hybrid`, and `verified` but all behave identically. `--max-pages` has no effect. See [FUTURE.md](FUTURE.md) for the verified and hybrid backend plans. - -### 1.3 Understanding the Output - -The transpiler produces a self-contained Rust source file that depends only on `herkos-runtime`. The output contains: - -``` -┌──────────────────────────────────────────────┐ -│ Generated output.rs │ -├──────────────────────────────────────────────┤ -│ use herkos_runtime::*; │ -│ │ -│ struct Globals { ... } ← mutable globals│ -│ const G1: i64 = 42; ← immutable │ -│ │ -│ fn func_0(...) { ... } ← Wasm functions │ -│ fn func_1(...) { ... } │ -│ │ -│ struct Module { │ -│ memory: IsolatedMemory, │ -│ globals: Globals, │ -│ table: Table, │ -│ } │ -│ │ -│ impl Module { ... } ← exports as │ -│ methods │ -│ trait ModuleImports { ... } ← required │ -│ capabilities │ -└──────────────────────────────────────────────┘ -``` - -### 1.4 Using Transpiled Code - -#### Direct inclusion - -```rust -use herkos_runtime::{IsolatedMemory, WasmResult}; - -include!("path/to/output.rs"); - -fn main() -> WasmResult<()> { - let mut module = Module::<256, 4>::new( - 16, // initial pages - Globals::default(), // module globals - Table::default(), // call table - )?; - - let result = module.my_function(42)?; - println!("Result: {}", result); - Ok(()) -} -``` - -#### Via build.rs (recommended for automated workflows) - -```rust -// build.rs -use std::env; -use std::path::PathBuf; - -fn main() { - let out_dir = env::var("OUT_DIR").unwrap(); - let out_path = PathBuf::from(&out_dir); - - println!("cargo:rerun-if-changed=wasm-modules/math.wasm"); - - let wasm_bytes = std::fs::read("wasm-modules/math.wasm").unwrap(); - let options = herkos::TranspileOptions::default(); - let rust_code = herkos::transpile(&wasm_bytes, &options).unwrap(); - std::fs::write(out_path.join("math_module.rs"), rust_code).unwrap(); -} -``` - -```rust -// src/main.rs -use herkos_runtime::WasmResult; -include!(concat!(env!("OUT_DIR"), "/math_module.rs")); - -fn main() -> WasmResult<()> { - let mut module = Module::<16, 0>::new(1, Globals::default(), Table::default())?; - let result = module.add(5, 3)?; - println!("Result: {}", result); - Ok(()) -} -``` - -When including multiple modules, wrap them in Rust modules to avoid name collisions: - -```rust -mod math { - include!(concat!(env!("OUT_DIR"), "/math_module.rs")); -} -mod crypto { - include!(concat!(env!("OUT_DIR"), "/crypto_module.rs")); -} -``` - -### 1.5 Example: C to Rust via Wasm - -```c -// math.c -int add(int a, int b) { return a + b; } -int multiply(int a, int b) { return a * b; } -``` - -```bash -clang --target=wasm32 -O2 -c math.c -o math.o -wasm-ld math.o -o math.wasm --no-entry -herkos math.wasm --output math.rs -``` - -```rust -use herkos_runtime::WasmResult; -include!("math.rs"); - -fn main() -> WasmResult<()> { - let mut module = Module::<16, 0>::new(1, Globals::default(), Table::default())?; - println!("2 + 3 = {}", module.add(2, 3)?); - println!("4 * 5 = {}", module.multiply(4, 5)?); - Ok(()) -} -``` - ---- - -## 2. Module Representation - -This section describes how WebAssembly concepts map to Rust types. This is the core abstraction layer — everything else (transpilation, integration, performance) builds on these types. - -### 2.1 Memory Model - -#### 2.1.1 Page Model - -WebAssembly linear memory is organized in pages of 64 KiB (65,536 bytes). A Wasm module declares an initial page count and an optional maximum page count. - -``` -Page size: 64 KiB (defined by the WebAssembly specification) -Initial size: declared in the Wasm module (e.g., 16 pages = 1 MiB) -Maximum size: declared in the Wasm module (e.g., 256 pages = 16 MiB) -``` - -#### 2.1.2 Rust Representation: `IsolatedMemory` - -> Implementation: [crates/herkos-runtime/src/memory.rs](../crates/herkos-runtime/src/memory.rs) - -```rust -const PAGE_SIZE: usize = 65536; - -struct IsolatedMemory { - pages: [[u8; PAGE_SIZE]; MAX_PAGES], - active_pages: usize, -} -``` - -**Design decisions**: - -| Decision | Rationale | -|----------|-----------| -| `MAX_PAGES` const generic | No heap allocation, `no_std` compatible, enables monomorphization | -| `active_pages` runtime tracking | Starts at initial page count, grows via `memory.grow`, bounds-checks against this | -| 2D array `[[u8; PAGE_SIZE]; MAX_PAGES]` | Avoids unstable `generic_const_exprs`. `as_flattened()` provides flat `&[u8]` views (stable Rust 1.80+) | -| No maximum → CLI configurable | If the Wasm module declares no maximum, the transpiler picks a default (configurable via `--max-pages`) | - -#### 2.1.3 Memory Access API - -All memory operations are flat — no `MemoryView` wrappers. One method per Wasm type, avoiding monomorphization of inner functions: - -```rust -impl IsolatedMemory { - // Safe: bounds-checked against active_pages * PAGE_SIZE - fn load_i32(&self, offset: usize) -> WasmResult; - fn load_i64(&self, offset: usize) -> WasmResult; - fn load_u8(&self, offset: usize) -> WasmResult; - fn load_u16(&self, offset: usize) -> WasmResult; - fn load_f32(&self, offset: usize) -> WasmResult; - fn load_f64(&self, offset: usize) -> WasmResult; - fn store_i32(&mut self, offset: usize, value: i32) -> WasmResult<()>; - fn store_i64(&mut self, offset: usize, value: i64) -> WasmResult<()>; - // ... and store_u8, store_u16, store_f32, store_f64 -} -``` - -Read-only guarantees are not a Wasm primitive — they are an analysis result. Static analysis can prove that certain regions (e.g., `.rodata` data segments) are never targeted by store instructions. This is relevant to the future verified backend (see [FUTURE.md](FUTURE.md)). - -#### 2.1.4 `memory.grow` Semantics - -```rust -impl IsolatedMemory { - fn grow(&mut self, delta: u32) -> i32 { - let old = self.active_pages; - let new = old.wrapping_add(delta as usize); - if new > MAX_PAGES { - return -1; - } - for page in &mut self.pages[old..new] { - page.fill(0); - } - self.active_pages = new; - old as i32 - } -} -``` - -No allocation occurs. New pages are zero-initialized per the Wasm spec. - -#### 2.1.5 Linear Memory Layout - -When C/C++ compiles to Wasm, the compiler organizes linear memory into conventional regions: - -``` -┌─────────────────────────────────────────┐ MAX_PAGES * PAGE_SIZE -│ (unused / growable) │ -├─────────────────────────────────────────┤ ← __stack_pointer (grows ↓) -│ Shadow Stack │ -│ (local variables, large structs, │ -│ spills, return values) │ -├─────────────────────────────────────────┤ -│ Heap (grows ↑) │ -│ (malloc / C++ new) │ -├─────────────────────────────────────────┤ -│ Data Segments │ -│ (.data, .rodata, .bss) │ -└─────────────────────────────────────────┘ 0 -``` - -Key points: -- Wasm's value stack only holds scalars (i32, i64, f32, f64). Large structs and address-taken locals live in the **shadow stack** in linear memory. -- A "pure" C function returning a large struct actually writes to its shadow stack frame via `i32.store` instructions — not pure with respect to memory. - -#### 2.1.6 Compile-Time Guarantees - -- **Spatial safety**: all memory accesses bounds-checked against `active_pages * PAGE_SIZE` -- **Temporal safety**: Rust's lifetime system prevents use-after-free -- **Isolation**: each module has its own `IsolatedMemory` instance — distinct types, distinct backing arrays, no cross-module access possible - -### 2.2 Module Types - -> Implementation: [crates/herkos-runtime/src/module.rs](../crates/herkos-runtime/src/module.rs) - -``` - ┌─────────────────────────────────────┐ - │ Module Taxonomy │ - ├──────────────────┬──────────────────┤ - │ │ │ - ┌─────┴─────┐ ┌──────┴──────┐ ┌──────┴──────┐ - │ Module │ │ Library │ │ Pure │ - │ (owns mem) │ │ Module │ │ (no memory) │ - │ │ │ (borrows) │ │ │ - └────────────┘ └─────────────┘ └─────────────┘ - Like a process Like a shared Pure computation - library -``` - -#### Process-like Module (owns memory) - -```rust -struct Module { - memory: IsolatedMemory, - globals: G, - table: Table, -} -``` - -#### Library Module (borrows memory) - -```rust -struct LibraryModule { - globals: G, - table: Table, - // no memory field — uses caller's memory -} -``` - -| Wasm declaration | Rust representation | Analogy | -|------------------|---------------------|---------| -| Module defines memory | `Module` owns `IsolatedMemory` | POSIX process | -| Module imports memory | `LibraryModule` borrows `&mut IsolatedMemory` | Shared library | -| Module has no memory | `LibraryModule` with no memory parameter | Pure computation | - -### 2.3 Globals and Tables - -> Implementation: [crates/herkos-runtime/src/table.rs](../crates/herkos-runtime/src/table.rs) - -#### Globals - -```rust -// Generated by the transpiler — one struct per module -struct Globals { - g0: i32, // (global (mut i32) ...) — mutable, lives in struct - // g1 is immutable → emitted as `const G1: i64 = 42;` instead -} -``` - -#### Tables - -```rust -struct Table { - entries: [Option; MAX_SIZE], - active_size: usize, -} - -struct FuncRef { - type_index: u32, // canonical type index for signature check - func_index: u32, // index into module function space → match dispatch -} -``` - -Tables are initialized from element segments during module construction: - -```rust -// From: (elem (i32.const 0) $add $sub $mul) -let mut table = Table::try_new(3); -table.set(0, Some(FuncRef { type_index: 0, func_index: 0 })).unwrap(); -table.set(1, Some(FuncRef { type_index: 0, func_index: 1 })).unwrap(); -table.set(2, Some(FuncRef { type_index: 0, func_index: 2 })).unwrap(); -``` - -### 2.4 Imports as Trait Bounds - -Capabilities are Rust **traits**, not bitflags. A Wasm module's imports become trait bounds on its functions: - -```rust -// Generated from: (import "env" "socket_open" (func ...)) -// (import "env" "socket_read" (func ...)) -trait SocketOps { - fn socket_open(&mut self, domain: i32, sock_type: i32) -> WasmResult; - fn socket_read(&mut self, fd: i32, buf_ptr: u32, len: u32) -> WasmResult; -} - -// Module function that calls socket imports requires the trait: -fn send_data( - host: &mut H, - memory: &mut IsolatedMemory, - // ... -) -> WasmResult { - let sock = host.socket_open(2, 1)?; - // ... -} - -// No imports → no host parameter, pure computation: -fn pure_math(a: i32, b: i32) -> i32 { a.wrapping_add(b) } -``` - -| Aspect | Bitflags (`const CAPS: u64`) | Traits | -|--------|------------------------------|--------| -| Granularity | Coarse (1 bit = 1 class) | Fine (exact function signatures) | -| Compile-time checking | Fails if bit not set | Fails if trait not implemented | -| Error messages | Opaque bit mismatch | Clear: "trait `SocketOps` not implemented" | -| Runtime cost | Zero | Zero (monomorphization) | -| Extensibility | Limited to 64 bits | Unlimited | -| Inter-module linking | Not supported | Natural via trait composition | - -### 2.5 Exports as Trait Implementations - -```rust -// Generated from: (export "transform" (func $transform)) -trait ImageLibExports { - fn transform(&mut self, ptr: u32, len: u32) -> WasmResult; - fn init(&mut self) -> WasmResult<()>; -} - -impl ImageLibExports for ImageModule { - fn transform(&mut self, ptr: u32, len: u32) -> WasmResult { - func_transform(&mut self.memory, &mut self.globals, ptr, len) - } - fn init(&mut self) -> WasmResult<()> { - func_init(&mut self.memory, &mut self.globals) - } -} -``` - -### 2.6 WASI Support - -WASI is a standard set of import traits shipped by `herkos-runtime`: - -```rust -trait WasiFd { - fn fd_read(&mut self, fd: i32, iovs: u32, iovs_len: u32, nread: u32) -> WasmResult; - fn fd_write(&mut self, fd: i32, iovs: u32, iovs_len: u32, nwritten: u32) -> WasmResult; - fn fd_close(&mut self, fd: i32) -> WasmResult; - // ... -} - -trait WasiClock { - fn clock_time_get(&mut self, clock_id: i32, precision: i64, time: u32) -> WasmResult; -} - -trait WasiRandom { - fn random_get(&mut self, buf: u32, len: u32) -> WasmResult; -} -``` - -The host implements whichever subset it supports: - -```rust -// Bare-metal: only fd_write (UART) and clock -struct EmbeddedHost { /* ... */ } -impl WasiFd for EmbeddedHost { /* UART-backed */ } -impl WasiClock for EmbeddedHost { /* hardware timer */ } - -// Full POSIX: everything -struct PosixHost { /* ... */ } -impl WasiFd for PosixHost { /* real file ops */ } -impl WasiClock for PosixHost { /* clock_gettime */ } -impl WasiRandom for PosixHost { /* /dev/urandom */ } -``` - -Custom platform-specific capabilities beyond WASI are just additional traits (e.g., `GpioOps`, `CanBusOps`). - -### 2.7 Isolation Guarantees - -The ownership model enforces freedom from interference structurally: - -``` -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ Module A │ │ Module B │ │ Library C │ -│ │ │ │ │ │ -│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ (no memory) │ -│ │ Memory A │ │ │ │ Memory B │ │ │ │ -│ │ (owned) │ │ │ │ (owned) │ │ │ Borrows caller │ -│ └─────────────┘ │ │ └─────────────┘ │ │ memory for │ -│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ duration of │ -│ │ Globals A │ │ │ │ Globals B │ │ │ each call │ -│ └─────────────┘ │ │ └─────────────┘ │ │ │ -└─────────────────┘ └─────────────────┘ └─────────────────┘ - ✗ cannot ✗ cannot ✓ borrows - access B access A one at a time -``` - -1. **Module with its own memory**: cannot access another module's memory — each owns a distinct `IsolatedMemory` instance -2. **Library module**: can only access the specific memory it was handed via `&mut` borrow. Cannot hold the reference past the call (lifetime enforced), cannot access a different module's memory -3. **Pure module**: no memory at all — the type system provides no memory access methods - -Inter-module calls lend memory for the duration of the call: - -```rust -let mut app = Module::::new(16, AppGlobals::default(), table)?; -let mut lib = LibraryModule::::new(LibGlobals::default(), table)?; - -// Caller's memory is borrowed for this call only. -// Rust borrow checker guarantees the library cannot store the reference. -let result = lib.call_export_transform(&mut app.memory, ptr, len)?; -``` - ---- - -## 3. Architecture - -### 3.1 Component Overview - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ herkos workspace │ -│ │ -│ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐ │ -│ │ herkos (CLI) │ │ herkos-runtime │ │ herkos-tests │ │ -│ │ ┌───────────┐ │ │ #![no_std] │ │ │ │ -│ │ │ Parser │ │ │ │ │ WAT/C/Rust │ │ -│ │ │(wasmparser)│ │ │ IsolatedMemory │ │ sources │ │ -│ │ ├───────────┤ │ │ Table, FuncRef │ │ → .wasm │ │ -│ │ │ IR Builder│ │ │ Module types │ │ → transpile │ │ -│ │ │ (SSA-form)│ │ │ WasmTrap │ │ → test │ │ -│ │ ├───────────┤ │ │ Wasm ops │ │ │ │ -│ │ │ Optimizer │ │ │ │ │ benches/ │ │ -│ │ ├───────────┤ │ └──────────────────┘ └────────────────┘ │ -│ │ │ Backend │ │ │ ▲ │ -│ │ │ (safe) │ │ │ depends on │ depends │ -│ │ ├───────────┤ │ │ │ on both │ -│ │ │ Codegen │ │ └─────────────────────┘ │ -│ │ └───────────┘ │ │ -│ └─────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -### 3.2 Runtime (`herkos-runtime`) - -> Source: [crates/herkos-runtime/src/](../crates/herkos-runtime/src/) - -The runtime is a `#![no_std]` crate providing the types that all transpiled code depends on. It has **zero external dependencies** in the default configuration. - -| Module | Provides | Reference | -|--------|----------|-----------| -| `memory.rs` | `IsolatedMemory`, load/store methods, `memory.grow`/`memory.size` | §2.1 | -| `table.rs` | `Table`, `FuncRef` | §2.3 | -| `module.rs` | `Module`, `LibraryModule` | §2.2 | -| `ops.rs` | Wasm arithmetic operations (`i32_div_s`, `i32_trunc_f32_s`, etc.) | §4.4 | -| `lib.rs` | `WasmTrap`, `WasmResult`, `ConstructionError`, `PAGE_SIZE` | §4.3 | - -**Constraints** (see [REQ_PLATFORM_NO_STD](REQUIREMENTS.md)): -- No heap allocation without the optional `alloc` feature gate -- No panics, no `format!`, no `String` -- Errors are `Result` only -- Optional `alloc` feature gate for targets with a global allocator - -**Runtime verification with Kani**: The runtime includes `#[kani::proof]` harnesses that verify core invariants (no panics on any input, correct grow semantics, load/store roundtrip). Run via `cargo kani`. See [crates/herkos-runtime/KANI.md](../crates/herkos-runtime/KANI.md). - -### 3.3 Transpiler (`herkos`) - -> Source: [crates/herkos/src/](../crates/herkos/src/) - -The transpiler converts `.wasm` binaries to Rust source code. The pipeline: - -``` -.wasm ──→ Parser ──→ IR Builder ──→ Optimizer ──→ Backend ──→ Codegen ──→ rustfmt - │ │ │ │ │ - │ wasmparser │ SSA-form IR │ dead block │ safe │ Rust source - │ crate │ per function │ elimination │ backend │ string - ▼ ▼ ▼ ▼ ▼ - ParsedModule ModuleInfo ModuleInfo Backend String - + IrFunctions (optimized) trait -``` - -#### 3.3.1 Parser - -> Source: [crates/herkos/src/parser/](../crates/herkos/src/parser/) - -Uses the `wasmparser` crate to extract module structure: types, functions, memories, tables, globals, imports, exports, data segments, element segments. - -**Design choice**: `wasmparser` only, not `wasm-tools` or `walrus`. Keeps the dependency tree small and avoids pulling in a full Wasm runtime. - -#### 3.3.2 IR (Intermediate Representation) - -> Source: [crates/herkos/src/ir/](../crates/herkos/src/ir/) - -An SSA-form IR that sits between Wasm bytecode and Rust source: - -``` - Wasm bytecode IR Rust source - ┌────────────────────────┐ ┌──────────────────────┐ ┌────────────────────────┐ - │ i32.const 5 │ │ v0 = Const(5) │ │ let v0: i32 = 5; │ - │ i32.const 3 │ │ v1 = Const(3) │ │ let v1: i32 = 3; │ - │ i32.add │ │ v2 = Add(v0, v1) │ │ let v2: i32 = │ - │ │ │ │ │ v0.wrapping_add(v1); │ - └────────────────────────┘ └──────────────────────┘ └────────────────────────┘ -``` - -Key types (defined in `ir/mod.rs` and `ir/types.rs`): -- `ModuleInfo` — complete module metadata (types, functions, memories, globals, imports, exports) -- `IrFunction` — one function's IR: blocks, instructions, locals, return type -- `IrBlock` — a basic block containing a sequence of `IrInstr` -- `IrInstr` — a single SSA instruction (Const, Add, Load, Store, Call, Branch, etc.) - -The builder (`ir/builder/`) translates Wasm instructions to IR. Each function is independent — enabling future parallelization (see §6.2). - -#### 3.3.3 Optimizer - -> Source: [crates/herkos/src/optimizer/](../crates/herkos/src/optimizer/) - -Currently implements dead block elimination. The optimizer operates on the IR before codegen. - -#### 3.3.4 Backend - -> Source: [crates/herkos/src/backend/](../crates/herkos/src/backend/) - -The backend trait abstracts code generation strategy. Currently only `SafeBackend` is implemented: - -- Emits 100% safe Rust -- Every memory access goes through bounds-checked wrappers returning `WasmResult` -- No verification metadata required - -For the planned verified and hybrid backends, see [FUTURE.md](FUTURE.md). - -#### 3.3.5 Code Generator - -> Source: [crates/herkos/src/codegen/](../crates/herkos/src/codegen/) - -Walks the IR and emits Rust source code: - -| Codegen module | Responsibility | -|---------------|----------------| -| `module.rs` | Module struct definition, constructor | -| `function.rs` | Function signatures, parameter threading | -| `instruction.rs` | IR instruction → Rust expression | -| `traits.rs` | Import trait generation | -| `export.rs` | Export method generation | -| `constructor.rs` | Module `new()` with data/element segment initialization | -| `types.rs` | Type mapping (Wasm types ↔ Rust types) | -| `utils.rs` | Shared utilities | - -### 3.4 Tests (`herkos-tests`) - -> Source: [crates/herkos-tests/](../crates/herkos-tests/) - -End-to-end test crate that compiles WAT/C/Rust sources to `.wasm`, transpiles them, and runs the output. - -#### Test pipeline - -``` -WAT / C / Rust source - │ - ▼ (build.rs) - .wasm binary - │ - ▼ (herkos::transpile) - Generated .rs - │ - ▼ (include! in test) - Compiled & tested -``` - -#### Test categories - -| Category | Test files | What's tested | -|----------|-----------|---------------| -| Arithmetic | `arithmetic.rs`, `numeric_ops.rs` | Wasm arithmetic, bitwise, comparison ops | -| Memory | `memory.rs`, `memory_grow.rs`, `subwidth_mem.rs` | Load/store, memory.grow, sub-width access | -| Control flow | `control_flow.rs`, `early_return.rs`, `select.rs`, `unreachable.rs` | Block, loop, if, br, br_table, select | -| Functions | `function_calls.rs`, `indirect_calls.rs` | Direct calls, call_indirect dispatch | -| Imports/Exports | `import_traits.rs`, `import_memory.rs`, `import_multi.rs`, `module_wrapper.rs` | Trait-based imports, module wrapper | -| Locals | `locals.rs`, `locals_aliasing.rs` | Local variable handling | -| E2E (C) | `c_e2e.rs`, `c_e2e_i64.rs`, `c_e2e_loops.rs`, `c_e2e_memory.rs` | Full C → Wasm → Rust pipeline | -| E2E (Rust) | `rust_e2e.rs`, `rust_e2e_control.rs`, `rust_e2e_i64.rs`, `rust_e2e_heavy_fibo.rs` | Pre-generated Rust modules | - -#### Running tests - -```bash -cargo test # all crates -cargo test -p herkos # transpiler unit tests -cargo test -p herkos-runtime # runtime unit tests -cargo test -p herkos-tests # integration & E2E tests -``` - -### 3.5 Benchmarks - -> Source: [crates/herkos-tests/benches/](../crates/herkos-tests/benches/) - -Performance benchmarks using Criterion. Currently includes Fibonacci benchmarks comparing transpiled Wasm execution against native Rust. - -```bash -cargo bench -p herkos-tests -``` - ---- - -## 4. Transpilation Rules - -This section describes how Wasm constructs map to Rust code in the safe backend. - -### 4.1 Function Translation - -Wasm functions become Rust functions. Module state is threaded through as parameters: - -```rust -// Wasm: (func $example (param i32) (result i32)) -// No imports → no host parameter -fn func_0( - memory: &mut IsolatedMemory, - globals: &mut Globals, - param0: i32, -) -> WasmResult { - // function body -} - -// Wasm: (func $send (param i32 i32) (result i32)) -// Calls imported functions → requires host with trait bounds -fn func_1( - memory: &mut IsolatedMemory, - globals: &mut Globals, - host: &mut H, - param0: i32, - param1: i32, -) -> WasmResult { - // can call host.socket_open(), host.fd_write(), etc. -} -``` - -Only state that the function actually uses is passed. A function with no memory omits `memory`; no table omits `table`; no mutable globals omits `globals`. - -### 4.2 Control Flow - -| Wasm | Rust | -|------|------| -| `block` | `'label: { ... }` labeled block | -| `loop` | `'label: loop { ... }` | -| `if / else` | `if condition { ... } else { ... }` | -| `br $label` | `break 'label` | -| `br_if $label` | `if condition { break 'label }` | -| `br_table` | `match index { 0 => break 'l0, 1 => break 'l1, _ => break 'default }` | - -All blocks are labeled to support Wasm's structured branch targets. - -### 4.3 Error Handling - -> Implementation: [crates/herkos-runtime/src/lib.rs](../crates/herkos-runtime/src/lib.rs) - -```rust -enum WasmTrap { - OutOfBounds, // Memory access out of bounds - DivisionByZero, // Integer division by zero - IntegerOverflow, // e.g., i32.trunc_f64_s on out-of-range float - Unreachable, // unreachable instruction executed - IndirectCallTypeMismatch, // call_indirect signature check failed - TableOutOfBounds, // Table access out of bounds - UndefinedElement, // Undefined element in table -} - -type WasmResult = Result; -``` - -No panics, no unwinding. The `?` operator propagates traps up the call stack. - -### 4.4 Arithmetic Operations - -> Implementation: [crates/herkos-runtime/src/ops.rs](../crates/herkos-runtime/src/ops.rs) - -Wasm arithmetic operations that can trap (division, remainder, truncation) return `WasmResult`: - -```rust -fn i32_div_s(a: i32, b: i32) -> WasmResult; // traps on /0 or overflow -fn i32_rem_u(a: i32, b: i32) -> WasmResult; // traps on /0 -fn i32_trunc_f32_s(a: f32) -> WasmResult; // traps on out-of-range -``` - -Non-trapping arithmetic uses Rust's wrapping operations (`wrapping_add`, `wrapping_mul`, etc.) per the Wasm spec. - -### 4.5 Function Calls - -#### 4.5.1 Direct Calls (`call`) - -Direct calls transpile to regular Rust function calls with state threaded through: - -```rust -// Wasm: call $func_3 (with 2 args on the stack) -v5 = func_3(memory, globals, table, v3, v4)?; -``` - -#### 4.5.2 Indirect Calls (`call_indirect`) - -`call_indirect` implements function pointers. The transpiler emits a static match dispatch: - -```rust -// Wasm: call_indirect (type $binop) ; expects (i32, i32) -> i32 -let __entry = table.get(v2 as u32)?; // lookup + bounds check -if __entry.type_index != 0 { // type signature check - return Err(WasmTrap::IndirectCallTypeMismatch); -} -v4 = match __entry.func_index { // static dispatch - 0 => func_0(v0, v1, table)?, // add - 1 => func_1(v0, v1, table)?, // sub - 2 => func_2(v0, v1, table)?, // mul - _ => return Err(WasmTrap::UndefinedElement), -}; -``` - -**Why match-based dispatch?** Function pointer arrays, `dyn Fn` trait objects, or computed gotos all require `unsafe`, heap allocation, or break `no_std` compatibility. A match statement is 100% safe, `no_std` compatible, and LLVM optimizes it to a jump table when arms are dense. - -The `_ =>` arm handles func_index values that don't match any function of the right type — a safety net for corrupted table entries. - -#### 4.5.3 Structural Type Equivalence - -The Wasm spec requires `call_indirect` to use **structural equivalence**: two type indices match if they have identical parameter and result types, regardless of index. - -``` -Type 0: (i32, i32) → i32 → canonical = 0 -Type 1: (i32, i32) → i32 → canonical = 0 (same signature as type 0) -Type 2: (i32) → i32 → canonical = 2 (new signature) -``` - -The transpiler builds a canonical type index mapping at transpile time. Both `FuncRef.type_index` and the type check use canonical indices. At runtime, the check is a simple integer comparison. - -### 4.6 Bulk Memory Operations - -> Implementation: [crates/herkos-runtime/src/memory.rs](../crates/herkos-runtime/src/memory.rs) lines 149–174 - -The WebAssembly bulk memory operations allow efficient copying and initialization of memory regions without scalar load/store loops. - -#### 4.6.1 `memory.fill` - -Fills a region of memory with a byte value. Per Wasm spec, only the low 8 bits of the value are used. - -```rust -impl IsolatedMemory { - pub fn fill(&mut self, dst: usize, val: u8, len: usize) -> WasmResult<()>; -} -``` - -Generated code: -```rust -// Wasm: memory.fill $dst $val $len -memory.fill(dst as usize, val as u8, len as usize)?; -``` - -Traps `OutOfBounds` if `[dst, dst + len)` exceeds active memory. Length zero is a no-op. - -#### 4.6.2 `memory.init` - -Copies data from a passive data segment into memory at runtime. Each data segment is stored as a constant `&'static [u8]` in the generated code. - -```rust -impl IsolatedMemory { - pub fn init_data_partial(&mut self, dst: usize, data: &[u8], src_offset: usize, len: usize) -> WasmResult<()>; -} -``` - -Generated code: -```rust -// Wasm: memory.init $data_segment $dst $src_offset $len -memory.init_data_partial(dst as usize, &DATA_SEGMENT_0, src_offset as usize, len as usize)?; -``` - -Traps `OutOfBounds` if either region (source or destination) exceeds bounds: -- Source: `[src_offset, src_offset + len)` must be within the data segment -- Destination: `[dst, dst + len)` must be within active memory - -#### 4.6.3 `data.drop` - -Marks a data segment as dropped (per Wasm spec). In the safe backend this is a no-op because data segments are stored as constant references and cannot actually be deallocated. - -```rust -// Wasm: data.drop $segment -// (no-op in safe backend — const slices persist) -``` - -In future verified and hybrid backends, `data.drop` may enable optimizations: proving that dropped segments are never accessed again could allow proving certain addresses as never-in-bounds. - ---- - -## 5. Integration - -### 5.1 Trait-Based Integration (Primary) - -The host instantiates modules and provides capabilities through trait implementations: - -```rust -struct MyHost { /* platform resources */ } -impl SocketOps for MyHost { /* ... */ } -impl WasiFd for MyHost { /* ... */ } - -let mut module = Module::::new(16, MyGlobals::default(), table)?; -let mut host = MyHost::new(); -let result = module.process_data(&mut host, ptr, len)?; -``` - -Full type safety, zero `unsafe`, zero-cost dispatch via monomorphization. - -### 5.2 The Env Context Pattern - -> Implementation: [crates/herkos-core/src/codegen/env.rs](../crates/herkos-core/src/codegen/env.rs) - -Generated modules use a unified **Env** context struct that bundles the host (generic parameter `H`) and mutable globals, simplifying parameter threading throughout function calls. - -```rust -// Generated by transpiler -pub struct Env<'a, H: ModuleHostTrait + ?Sized> { - pub host: &'a mut H, - pub globals: &'a mut Globals, -} - -// Every function that needs imports or mutable state receives Env -fn process( - memory: &mut IsolatedMemory, - env: &mut Env, - input: i32, -) -> WasmResult { - // Call imported function via trait - let result = env.host.some_import(input)?; - // Read/write mutable global - env.globals.my_global += 1; - Ok(result) -} -``` - -**Design rationale:** -- **Unified state**: Avoids threading `host`, `globals`, and other mutable state as separate parameters -- **Type safety**: All imports must be present in the host's trait implementation — checked at compile time -- **Zero overhead**: The Env struct is a thin wrapper; LLVM inlines and optimizes away the indirection -- **Extensibility**: Adding new imports or globals requires only modifying the trait, not all function signatures - -**Generated trait:** - -```rust -pub trait ModuleHostTrait { - // One method per function import - fn imported_function(&mut self, arg: i32) -> WasmResult; - - // Getter/setter methods for each imported global - fn get_imported_global(&self) -> i32; - fn set_imported_global(&mut self, value: i32); -} -``` - -### 5.4 C-Compatible ABI (Optional) - -For integration with non-Rust systems, an optional `extern "C"` wrapper erases generics: - -```rust -#[no_mangle] -pub extern "C" fn module_new(initial_pages: u32) -> *mut OpaqueModule { /* ... */ } - -#[no_mangle] -pub extern "C" fn module_call( - instance: *mut OpaqueModule, - function_index: u32, - args: *const i64, - args_len: usize, - result: *mut i64, -) -> i32 { /* 0 = success, non-zero = WasmTrap discriminant */ } -``` - -The C ABI wrapper uses `unsafe` and raw pointers. Capability enforcement still applies inside — the wrapper calls through trait-bounded functions. This is an escape hatch, not the default. - -### 5.5 Native Rust Integration - -Native Rust code integrates by implementing import traits directly: - -```rust -trait GpioOps { - fn gpio_set(&mut self, pin: u32, value: bool) -> WasmResult<()>; - fn gpio_read(&self, pin: u32) -> WasmResult; -} - -struct EmbeddedHost { /* ... */ } -impl GpioOps for EmbeddedHost { /* ... */ } -``` - ---- - -## 6. Performance - -### 6.1 Overhead - -| Backend | Overhead | Source | Status | -|---------|----------|--------|--------| -| Safe | 15–30% | Runtime bounds check on every memory access | Implemented | -| Verified | 0–5% | Function call indirection only | Planned ([FUTURE.md](FUTURE.md)) | -| Hybrid | 5–15% | Mix of checked and proven accesses | Planned ([FUTURE.md](FUTURE.md)) | - -### 6.2 Monomorphization Bloat Mitigation - -Each distinct `MAX_PAGES` and trait bound combination generates separate code. Mitigation strategies: - -#### 1. Outline pattern (mandatory for runtime) - -Move logic into non-generic inner functions. Generic wrapper is a thin shell: - -```rust -#[inline(never)] -fn load_i32_inner(memory: &[u8], active_bytes: usize, offset: usize) -> WasmResult { - // ONE copy in the binary -} - -impl IsolatedMemory { - #[inline(always)] - fn load_i32(&self, offset: usize) -> WasmResult { - load_i32_inner(self.pages.as_flattened(), self.active_pages * PAGE_SIZE, offset) - } -} -``` - -#### 2. `MAX_PAGES` normalization - -Use standard sizes (16, 64, 256, 1024) instead of exact declared maximums. Two modules with `MAX_PAGES=253` and `MAX_PAGES=260` both use `MAX_PAGES=256`. - -#### 3. Trait objects for cold paths - -Use `&mut dyn Trait` instead of generics for rarely-called code (error handling, initialization). - -#### 4. LTO - -Link-time optimization eliminates unreachable monomorphized copies. - -### 6.3 Transpiler Parallelization - -IR building and code generation are embarrassingly parallel — each function is independent: - -``` - ┌──────────┐ - │ Parse │ (sequential) - └────┬─────┘ - │ - ┌─────────────┼───────────┐ - ▼ ▼ ▼ - ┌──────────┐ ┌──────────┐ ┌──────────┐ - │ IR Build │ │ IR Build │ │ IR Build │ (parallel) - │ func_0 │ │ func_1 │ │ func_N │ - └────┬─────┘ └────┬─────┘ └────┬─────┘ - │ │ │ - ▼ ▼ ▼ - ┌──────────┐ ┌──────────┐ ┌──────────┐ - │ Codegen │ │ Codegen │ │ Codegen │ (parallel) - │ func_0 │ │ func_1 │ │ func_N │ - └────┬─────┘ └────┬─────┘ └────┬─────┘ - │ │ │ - └────────────┼────────────┘ - ▼ - ┌──────────┐ - │ Assemble │ (sequential) - └──────────┘ -``` - -Activation heuristic: use `rayon` parallel iterators when the module has 20+ functions. Output is deterministic regardless of thread count (`par_iter().enumerate()` preserves order). - -### 6.4 Comparison to Alternatives - -| Approach | Runtime Overhead | Isolation Strength | `unsafe` in output | -|----------|-----------------|-------------------|--------------------| -| MMU/MPU | 10–50% (context switches) | Strong (hardware) | N/A | -| herkos (safe) | 15–30% | Strong (runtime checks) | None | -| herkos (verified, planned) | 0–5% | Strong (formal proofs) | Yes — proof-justified | -| WebAssembly runtime | 20–100% | Strong (runtime sandbox) | N/A | -| Software fault isolation | 10–30% | Medium (runtime) | N/A | - ---- - -## 7. Security Properties - -### 7.1 Protected Against - -- **Memory corruption**: buffer overflows, use-after-free — prevented by bounds-checked access and Rust's ownership system -- **Unauthorized resource access**: files, network, system calls — prevented by trait-based capability enforcement -- **Cross-module interference**: freedom from interference — enforced by memory ownership isolation -- **ROP attacks**: no function pointers in generated code — all dispatch is static match - -### 7.2 Not Protected Against (current scope) - -- Logic bugs in the original C/C++ code -- Side-channel attacks (timing, cache) -- Resource exhaustion (infinite loops, memory leaks within bounds) — see [FUTURE.md](FUTURE.md) §3 for temporal isolation plans -- Timing interference — spatial isolation only, not temporal - -### 7.3 Relationship to Safety Standards - -This pipeline produces **evidence** for a freedom-from-interference argument: -- Transpiled Rust source is auditable -- Isolation boundary is the Rust type system — well-understood, no runtime configuration dependency -- **This tool does not replace a formal safety case.** It provides a compile-time isolation mechanism and associated evidence that can be used as part of one. - ---- - -## 8. Open Questions - -1. How to handle C++ exceptions in WebAssembly? -2. How to represent and verify concurrent access patterns? -3. Should we support dynamic linking of transpiled modules? -4. What level of C/C++ standard library should be supported? - ---- - -## 9. References - -- WebAssembly Specification: https://webassembly.github.io/spec/ -- Rust Reference: https://doc.rust-lang.org/reference/ -- Software Fault Isolation: Wahbe et al., 1993 -- Proof-Carrying Code: Necula & Lee, 1996 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..7fbe754 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,38 @@ +# -- Project information ------------------------------------------------------- + +project = "herkos" +copyright = "2025-2026, herkos contributors" +author = "herkos contributors" + +# -- General configuration ----------------------------------------------------- + +extensions = [ + "myst_parser", + "sphinx_needs", + "sphinxcontrib.mermaid", +] + +source_suffix = { + ".md": "markdown", + ".rst": "restructuredtext", +} + +master_doc = "index" +exclude_patterns = ["_build", ".venv", "scripts"] + +# -- MyST configuration -------------------------------------------------------- + +myst_enable_extensions = [ + "colon_fence", + "fieldlist", +] + +myst_heading_anchors = 3 + +# -- sphinx-needs configuration ------------------------------------------------ + +needs_from_toml = "ubproject.toml" + +# -- HTML output --------------------------------------------------------------- + +html_theme = "alabaster" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..d6d8a4b --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,36 @@ +herkos documentation +==================== + +herkos is a compilation pipeline that transforms WebAssembly modules into memory-safe Rust code with compile-time isolation guarantees, replacing runtime hardware-based memory protection (MMU/MPU) with type-system-enforced safety. + +.. mermaid:: + + flowchart TD + A["C/C++ Source"] --> B["WebAssembly (Wasm)"] + B --> C["Rust Transpiler + Runtime"] + C --> D["Safe Rust Binary"] + +Systems that mix components of different trust or criticality levels require **freedom from interference**: the guarantee that one module cannot corrupt the state of another. Hardware isolation mechanisms (MMU, MPU, hypervisors) provide this today, but at a cost in performance, energy, and certification complexity. + +herkos takes a different approach: **move the isolation guarantee from runtime hardware to compile-time type system enforcement**. If the Rust compiler accepts the transpiled code, isolation is guaranteed — no MMU, no context switches, no runtime overhead for proven accesses. + +Goals +----- + +- Achieve memory safety and inter-module isolation guarantees at compile time rather than runtime +- Provide performance competitive with or better than hardware-based isolation +- Provide a migration path for existing C/C++ codebases toward provable isolation without full rewrites +- Enable capability-based security enforced through the type system (freedom from interference by construction) +- Support incremental adoption: start with the safe backend (runtime checks, no proofs needed), progressively move to verified as proof coverage improves + +Sections +-------- + +.. toctree:: + :maxdepth: 2 + + GETTING_STARTED + REQUIREMENTS + specification/index + FUTURE + traceability/index diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..66c29e1 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx>=8.0 +myst-parser>=3.0 +sphinx-needs>=4.0 +sphinxcontrib-mermaid>=0.9 diff --git a/docs/scripts/generate_all.py b/docs/scripts/generate_all.py new file mode 100644 index 0000000..005b873 --- /dev/null +++ b/docs/scripts/generate_all.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +"""Generate auto-generated sphinx-needs files for herkos traceability.""" + +import subprocess +import sys +from pathlib import Path + +SCRIPTS_DIR = Path(__file__).parent + +def main(): + scripts = [ + SCRIPTS_DIR / "generate_wasm_spec_needs.py", + ] + + for script in scripts: + if script.exists(): + print(f"Running {script.name}...") + subprocess.check_call([sys.executable, str(script)]) + else: + print(f"Skipping {script.name} (not yet created)") + +if __name__ == "__main__": + main() diff --git a/docs/scripts/generate_wasm_spec_needs.py b/docs/scripts/generate_wasm_spec_needs.py new file mode 100644 index 0000000..a4bb778 --- /dev/null +++ b/docs/scripts/generate_wasm_spec_needs.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Generate wasm_spec needs for numeric instructions from wasm_1_0_instructions.toml. + +Reads the curated TOML data file (derived from the W3C WebAssembly Core +Specification 1.0) and produces RST with .. wasm_spec:: directives. +""" + +import sys + +if sys.version_info >= (3, 11): + import tomllib +else: + try: + import tomllib + except ImportError: + import tomli as tomllib # type: ignore[no-redef] + +from pathlib import Path + +SCRIPTS_DIR = Path(__file__).parent +TOML_PATH = SCRIPTS_DIR / "wasm_1_0_instructions.toml" +OUTPUT_PATH = SCRIPTS_DIR.parent / "traceability/wasm_spec/_gen" / "instructions_numeric.rst" + + +def make_id(prefix: str, op: str) -> str: + """Convert e.g. ('i32', 'div_s') to 'WASM_I32_DIV_S'.""" + return f"WASM_{prefix.upper()}_{op.upper()}" + + +def make_opcode(prefix: str, op: str) -> str: + """Convert e.g. ('i32', 'div_s') to 'i32.div_s'.""" + return f"{prefix}.{op}" + + +def rst_heading(text: str, char: str) -> list[str]: + """Return RST heading lines (text + underline).""" + return [text, char * len(text), ""] + + +def generate_grouped_section(prefix: str, ops: list[str], section: str, + tags: list[str]) -> list[str]: + """Generate .. wasm_spec:: directives for a group of same-prefix instructions.""" + lines = [] + for op in ops: + need_id = make_id(prefix, op) + opcode = make_opcode(prefix, op) + tag_str = ", ".join(tags) + lines.append(f".. wasm_spec:: {opcode}") + lines.append(f" :id: {need_id}") + lines.append(f" :wasm_section: {section}") + lines.append(f" :wasm_opcode: {opcode}") + lines.append(f" :tags: {tag_str}") + lines.append("") + lines.append(f" Wasm 1.0: ``{opcode}`` instruction.") + lines.append("") + return lines + + +def generate_conversions(data: dict) -> list[str]: + """Generate .. wasm_spec:: directives for conversion instructions.""" + lines = [] + section = data["section"] + base_tags = data["tags"] + for entry in data["ops"]: + name = entry["name"] + need_id = f"WASM_{entry['id_suffix']}" + desc = entry["desc"] + tag_str = ", ".join(base_tags) + lines.append(f".. wasm_spec:: {name}") + lines.append(f" :id: {need_id}") + lines.append(f" :wasm_section: {section}") + lines.append(f" :wasm_opcode: {name}") + lines.append(f" :tags: {tag_str}") + lines.append("") + lines.append(f" Wasm 1.0: ``{name}`` — {desc}.") + lines.append("") + return lines + + +def main(): + with open(TOML_PATH, "rb") as f: + data = tomllib.load(f) + + lines = [ + *rst_heading("Numeric Instructions", "="), + "Wasm 1.0 numeric instructions (§2.4.1): constants, unary, binary,", + "test, comparison, and conversion operations.", + "", + "Source: `W3C WebAssembly Core Specification 1.0, §2.4.1" + " `_", + "", + ] + + # Constants + lines.extend(rst_heading("Constants", "-")) + for type_key in ["i32", "i64", "f32", "f64"]: + const_data = data["constants"][type_key] + tags = const_data["tags"] + section = data["constants"]["section"] + for op in const_data["ops"]: + lines.extend(generate_grouped_section(type_key, [op], section, tags)) + + # Per-type instruction groups + for type_key in ["i32", "i64"]: + lines.extend(rst_heading(f"{type_key} Instructions", "-")) + + for group_key in [f"{type_key}_unary", f"{type_key}_test", + f"{type_key}_binop", f"{type_key}_compare"]: + group = data[group_key] + lines.extend(generate_grouped_section( + group["prefix"], group["ops"], group["section"], group["tags"] + )) + + for type_key in ["f32", "f64"]: + lines.extend(rst_heading(f"{type_key} Instructions", "-")) + + for group_key in [f"{type_key}_unary", f"{type_key}_binop", + f"{type_key}_compare"]: + group = data[group_key] + lines.extend(generate_grouped_section( + group["prefix"], group["ops"], group["section"], group["tags"] + )) + + # Conversions + lines.extend(rst_heading("Conversions", "-")) + lines.extend(generate_conversions(data["conversions"])) + + OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) + OUTPUT_PATH.write_text("\n".join(lines)) + print(f"Generated {OUTPUT_PATH} with numeric instruction needs") + + +if __name__ == "__main__": + main() diff --git a/docs/scripts/test_links.toml b/docs/scripts/test_links.toml new file mode 100644 index 0000000..3d6ead1 --- /dev/null +++ b/docs/scripts/test_links.toml @@ -0,0 +1,209 @@ +# Mapping of test files to the WASM_* spec needs they verify. +# Used by generate_test_needs.py to populate :verifies: links. +# +# Format: [filename_without_extension] +# verifies = ["WASM_ID_1", "WASM_ID_2", ...] + +[arithmetic] +verifies = [ + "WASM_I32_ADD", "WASM_I32_SUB", "WASM_I32_MUL", + "WASM_I32_CONST", "WASM_I64_ADD", "WASM_I64_CONST", + "WASM_NOP", "WASM_CALL", + "WASM_EXEC_INTEGER_OPS", +] + +[bulk_memory] +verifies = [ + "WASM_EXEC_MEMORY", +] + +[c_e2e] +verifies = [ + "WASM_I32_ADD", "WASM_I32_SUB", "WASM_I32_MUL", + "WASM_I32_DIV_S", "WASM_I32_REM_S", + "WASM_I32_AND", "WASM_I32_OR", "WASM_I32_XOR", + "WASM_I32_SHL", "WASM_I32_SHR_U", + "WASM_I64_ADD", + "WASM_MOD_EXPORTS", "WASM_MOD_FUNCTIONS", +] + +[c_e2e_i64] +verifies = [ + "WASM_I64_MUL", "WASM_I64_SUB", "WASM_I64_DIV_S", + "WASM_I64_REM_S", "WASM_I64_AND", "WASM_I64_OR", "WASM_I64_XOR", + "WASM_I64_SHL", "WASM_I64_SHR_S", +] + +[c_e2e_loops] +verifies = [ + "WASM_LOOP", "WASM_BR_IF", "WASM_IF", "WASM_BLOCK", + "WASM_EXEC_CONTROL", +] + +[c_e2e_memory] +verifies = [ + "WASM_I32_LOAD", "WASM_I32_STORE", + "WASM_EXEC_MEMORY", +] + +[call_import_transitive] +verifies = [ + "WASM_CALL", "WASM_MOD_IMPORTS", +] + +[control_flow] +verifies = [ + "WASM_IF", "WASM_BLOCK", "WASM_LOOP", "WASM_BR_IF", + "WASM_EXEC_CONTROL", +] + +[early_return] +verifies = [ + "WASM_RETURN", "WASM_IF", + "WASM_EXEC_CONTROL", +] + +[function_calls] +verifies = [ + "WASM_CALL", "WASM_CALL_INDIRECT", + "WASM_GLOBAL_GET", "WASM_GLOBAL_SET", + "WASM_I32_LOAD", "WASM_I32_STORE", + "WASM_I64_ADD", + "WASM_EXEC_CALLS", +] + +[import_memory] +verifies = [ + "WASM_MOD_IMPORTS", "WASM_MOD_MEMORIES", + "WASM_MEMORY_SIZE", "WASM_MEMORY_GROW", + "WASM_I32_LOAD", "WASM_I32_STORE", +] + +[import_multi] +verifies = [ + "WASM_MOD_IMPORTS", "WASM_CALL", + "WASM_EXEC_CALLS", +] + +[import_traits] +verifies = [ + "WASM_MOD_IMPORTS", "WASM_MOD_EXPORTS", + "WASM_EXTERNAL_TYPE", +] + +[indirect_call_import] +verifies = [ + "WASM_CALL_INDIRECT", "WASM_MOD_IMPORTS", + "WASM_MOD_TABLES", "WASM_MOD_ELEM", +] + +[indirect_calls] +verifies = [ + "WASM_CALL_INDIRECT", + "WASM_MOD_TABLES", "WASM_MOD_ELEM", + "WASM_EXEC_CALLS", +] + +[inter_module_lending] +verifies = [ + "WASM_MOD_IMPORTS", "WASM_MOD_MEMORIES", + "WASM_MEMORY_GROW", +] + +[locals] +verifies = [ + "WASM_LOCAL_GET", "WASM_LOCAL_SET", "WASM_LOCAL_TEE", + "WASM_EXEC_VARIABLE", +] + +[locals_aliasing] +verifies = [ + "WASM_LOCAL_GET", "WASM_LOCAL_SET", "WASM_LOCAL_TEE", +] + +[memory] +verifies = [ + "WASM_I32_LOAD", "WASM_I32_STORE", + "WASM_EXEC_MEMORY", +] + +[memory_grow] +verifies = [ + "WASM_MEMORY_SIZE", "WASM_MEMORY_GROW", + "WASM_EXEC_MEMORY", +] + +[module_wrapper] +verifies = [ + "WASM_MOD_GLOBALS", "WASM_MOD_DATA", + "WASM_GLOBAL_GET", + "WASM_EXEC_INSTANTIATION", +] + +[numeric_ops] +verifies = [ + "WASM_I64_DIV_S", "WASM_I64_AND", "WASM_I64_SHL", + "WASM_I64_LT_S", "WASM_I64_CLZ", "WASM_I64_ROTL", + "WASM_I64_REM_U", + "WASM_F64_DIV", "WASM_F64_MIN", "WASM_F64_LT", + "WASM_F64_SQRT", "WASM_F64_FLOOR", "WASM_F64_CEIL", "WASM_F64_NEG", + "WASM_I32_WRAP_I64", "WASM_I64_EXTEND_I32_S", "WASM_I64_EXTEND_I32_U", + "WASM_EXEC_INTEGER_OPS", "WASM_EXEC_FLOAT_OPS", "WASM_EXEC_CONVERSIONS", +] + +[rust_e2e] +verifies = [ + "WASM_I32_ADD", "WASM_I32_SUB", "WASM_I32_MUL", + "WASM_I32_AND", "WASM_I32_OR", "WASM_I32_XOR", + "WASM_I32_SHL", "WASM_I32_SHR_U", + "WASM_I64_ADD", + "WASM_MOD_EXPORTS", "WASM_MOD_FUNCTIONS", +] + +[rust_e2e_control] +verifies = [ + "WASM_LOOP", "WASM_BR_IF", "WASM_IF", "WASM_BLOCK", + "WASM_EXEC_CONTROL", +] + +[rust_e2e_heavy_fibo] +verifies = [ + "WASM_CALL", "WASM_I32_ADD", + "WASM_I32_LOAD", "WASM_I32_STORE", + "WASM_EXEC_CALLS", +] + +[rust_e2e_i64] +verifies = [ + "WASM_I64_MUL", "WASM_I64_SUB", + "WASM_I64_AND", "WASM_I64_OR", "WASM_I64_XOR", + "WASM_I64_SHL", "WASM_I64_SHR_S", +] + +[rust_e2e_memory_bench] +verifies = [ + "WASM_I32_LOAD", "WASM_I32_STORE", + "WASM_EXEC_MEMORY", +] + +[select] +verifies = [ + "WASM_SELECT", + "WASM_EXEC_PARAMETRIC", +] + +[subwidth_mem] +verifies = [ + "WASM_I32_LOAD8_S", "WASM_I32_LOAD8_U", + "WASM_I32_LOAD16_S", "WASM_I32_LOAD16_U", + "WASM_I32_STORE8", "WASM_I32_STORE16", + "WASM_I64_LOAD8_S", "WASM_I64_LOAD8_U", + "WASM_I64_LOAD32_S", "WASM_I64_LOAD32_U", + "WASM_I64_STORE32", +] + +[unreachable] +verifies = [ + "WASM_UNREACHABLE", + "WASM_EXEC_CONTROL", +] diff --git a/docs/scripts/wasm_1_0_instructions.toml b/docs/scripts/wasm_1_0_instructions.toml new file mode 100644 index 0000000..69f90fc --- /dev/null +++ b/docs/scripts/wasm_1_0_instructions.toml @@ -0,0 +1,248 @@ +# Wasm 1.0 Instruction Index +# Source: W3C WebAssembly Core Specification 1.0 (https://www.w3.org/TR/wasm-core-1/) +# Each entry produces a {wasm_spec} need in the generated output. + +# -- Constants (§2.4.1) -------------------------------------------------------- + +[constants] +section = "§2.4.1" + +[constants.i32] +ops = ["const"] +tags = ["numeric", "i32", "const"] + +[constants.i64] +ops = ["const"] +tags = ["numeric", "i64", "const"] + +[constants.f32] +ops = ["const"] +tags = ["numeric", "f32", "const"] + +[constants.f64] +ops = ["const"] +tags = ["numeric", "f64", "const"] + +# -- i32 Numeric Instructions (§2.4.1) ---------------------------------------- + +[i32_unary] +section = "§2.4.1" +prefix = "i32" +tags = ["numeric", "i32", "unary"] +ops = ["clz", "ctz", "popcnt"] + +[i32_test] +section = "§2.4.1" +prefix = "i32" +tags = ["numeric", "i32", "test"] +ops = ["eqz"] + +[i32_binop] +section = "§2.4.1" +prefix = "i32" +tags = ["numeric", "i32", "binop"] +ops = ["add", "sub", "mul", "div_s", "div_u", "rem_s", "rem_u", "and", "or", "xor", "shl", "shr_s", "shr_u", "rotl", "rotr"] + +[i32_compare] +section = "§2.4.1" +prefix = "i32" +tags = ["numeric", "i32", "comparison"] +ops = ["eq", "ne", "lt_s", "lt_u", "gt_s", "gt_u", "le_s", "le_u", "ge_s", "ge_u"] + +# -- i64 Numeric Instructions (§2.4.1) ---------------------------------------- + +[i64_unary] +section = "§2.4.1" +prefix = "i64" +tags = ["numeric", "i64", "unary"] +ops = ["clz", "ctz", "popcnt"] + +[i64_test] +section = "§2.4.1" +prefix = "i64" +tags = ["numeric", "i64", "test"] +ops = ["eqz"] + +[i64_binop] +section = "§2.4.1" +prefix = "i64" +tags = ["numeric", "i64", "binop"] +ops = ["add", "sub", "mul", "div_s", "div_u", "rem_s", "rem_u", "and", "or", "xor", "shl", "shr_s", "shr_u", "rotl", "rotr"] + +[i64_compare] +section = "§2.4.1" +prefix = "i64" +tags = ["numeric", "i64", "comparison"] +ops = ["eq", "ne", "lt_s", "lt_u", "gt_s", "gt_u", "le_s", "le_u", "ge_s", "ge_u"] + +# -- f32 Numeric Instructions (§2.4.1) ---------------------------------------- + +[f32_unary] +section = "§2.4.1" +prefix = "f32" +tags = ["numeric", "f32", "unary"] +ops = ["abs", "neg", "sqrt", "ceil", "floor", "trunc", "nearest"] + +[f32_binop] +section = "§2.4.1" +prefix = "f32" +tags = ["numeric", "f32", "binop"] +ops = ["add", "sub", "mul", "div", "min", "max", "copysign"] + +[f32_compare] +section = "§2.4.1" +prefix = "f32" +tags = ["numeric", "f32", "comparison"] +ops = ["eq", "ne", "lt", "gt", "le", "ge"] + +# -- f64 Numeric Instructions (§2.4.1) ---------------------------------------- + +[f64_unary] +section = "§2.4.1" +prefix = "f64" +tags = ["numeric", "f64", "unary"] +ops = ["abs", "neg", "sqrt", "ceil", "floor", "trunc", "nearest"] + +[f64_binop] +section = "§2.4.1" +prefix = "f64" +tags = ["numeric", "f64", "binop"] +ops = ["add", "sub", "mul", "div", "min", "max", "copysign"] + +[f64_compare] +section = "§2.4.1" +prefix = "f64" +tags = ["numeric", "f64", "comparison"] +ops = ["eq", "ne", "lt", "gt", "le", "ge"] + +# -- Conversion Instructions (§2.4.1) ----------------------------------------- + +[conversions] +section = "§2.4.1" +tags = ["numeric", "conversion"] + +# Each entry is: [opcode, description] +[[conversions.ops]] +name = "i32.wrap_i64" +id_suffix = "I32_WRAP_I64" +desc = "i64 to i32 (truncate to low 32 bits)" + +[[conversions.ops]] +name = "i64.extend_i32_s" +id_suffix = "I64_EXTEND_I32_S" +desc = "i32 to i64 (sign-extend)" + +[[conversions.ops]] +name = "i64.extend_i32_u" +id_suffix = "I64_EXTEND_I32_U" +desc = "i32 to i64 (zero-extend)" + +[[conversions.ops]] +name = "i32.trunc_f32_s" +id_suffix = "I32_TRUNC_F32_S" +desc = "f32 to i32 (signed, trapping)" + +[[conversions.ops]] +name = "i32.trunc_f32_u" +id_suffix = "I32_TRUNC_F32_U" +desc = "f32 to i32 (unsigned, trapping)" + +[[conversions.ops]] +name = "i32.trunc_f64_s" +id_suffix = "I32_TRUNC_F64_S" +desc = "f64 to i32 (signed, trapping)" + +[[conversions.ops]] +name = "i32.trunc_f64_u" +id_suffix = "I32_TRUNC_F64_U" +desc = "f64 to i32 (unsigned, trapping)" + +[[conversions.ops]] +name = "i64.trunc_f32_s" +id_suffix = "I64_TRUNC_F32_S" +desc = "f32 to i64 (signed, trapping)" + +[[conversions.ops]] +name = "i64.trunc_f32_u" +id_suffix = "I64_TRUNC_F32_U" +desc = "f32 to i64 (unsigned, trapping)" + +[[conversions.ops]] +name = "i64.trunc_f64_s" +id_suffix = "I64_TRUNC_F64_S" +desc = "f64 to i64 (signed, trapping)" + +[[conversions.ops]] +name = "i64.trunc_f64_u" +id_suffix = "I64_TRUNC_F64_U" +desc = "f64 to i64 (unsigned, trapping)" + +[[conversions.ops]] +name = "f32.convert_i32_s" +id_suffix = "F32_CONVERT_I32_S" +desc = "i32 to f32 (signed)" + +[[conversions.ops]] +name = "f32.convert_i32_u" +id_suffix = "F32_CONVERT_I32_U" +desc = "i32 to f32 (unsigned)" + +[[conversions.ops]] +name = "f32.convert_i64_s" +id_suffix = "F32_CONVERT_I64_S" +desc = "i64 to f32 (signed)" + +[[conversions.ops]] +name = "f32.convert_i64_u" +id_suffix = "F32_CONVERT_I64_U" +desc = "i64 to f32 (unsigned)" + +[[conversions.ops]] +name = "f64.convert_i32_s" +id_suffix = "F64_CONVERT_I32_S" +desc = "i32 to f64 (signed)" + +[[conversions.ops]] +name = "f64.convert_i32_u" +id_suffix = "F64_CONVERT_I32_U" +desc = "i32 to f64 (unsigned)" + +[[conversions.ops]] +name = "f64.convert_i64_s" +id_suffix = "F64_CONVERT_I64_S" +desc = "i64 to f64 (signed)" + +[[conversions.ops]] +name = "f64.convert_i64_u" +id_suffix = "F64_CONVERT_I64_U" +desc = "i64 to f64 (unsigned)" + +[[conversions.ops]] +name = "f32.demote_f64" +id_suffix = "F32_DEMOTE_F64" +desc = "f64 to f32" + +[[conversions.ops]] +name = "f64.promote_f32" +id_suffix = "F64_PROMOTE_F32" +desc = "f32 to f64" + +[[conversions.ops]] +name = "i32.reinterpret_f32" +id_suffix = "I32_REINTERPRET_F32" +desc = "f32 to i32 (bitcast)" + +[[conversions.ops]] +name = "i64.reinterpret_f64" +id_suffix = "I64_REINTERPRET_F64" +desc = "f64 to i64 (bitcast)" + +[[conversions.ops]] +name = "f32.reinterpret_i32" +id_suffix = "F32_REINTERPRET_I32" +desc = "i32 to f32 (bitcast)" + +[[conversions.ops]] +name = "f64.reinterpret_i64" +id_suffix = "F64_REINTERPRET_I64" +desc = "i64 to f64 (bitcast)" diff --git a/docs/specification/architecture.rst b/docs/specification/architecture.rst new file mode 100644 index 0000000..894c187 --- /dev/null +++ b/docs/specification/architecture.rst @@ -0,0 +1,359 @@ +.. _architecture: + +Architecture +============ + +Component Overview +------------------ + +.. code-block:: text + + ┌───────────────────────────────────────────────────────────────────────────┐ + │ herkos workspace │ + │ │ + │ ┌──────────────┐ ┌────────────────────────┐ ┌──────────────────────┐ │ + │ │ herkos (CLI) │ │ herkos-core │ │ herkos-runtime │ │ + │ │ │ │ │ │ #![no_std] │ │ + │ │ clap CLI │ │ ┌──────────────────┐ │ │ │ │ + │ │ arg parsing │ │ │ Parser │ │ │ IsolatedMemory │ │ + │ │ │ │ │ (wasmparser) │ │ │ Table, FuncRef │ │ + │ │ calls │ │ ├──────────────────┤ │ │ Module types │ │ + │ │ transpile() ├─►│ │ IR Builder │ │ │ WasmTrap │ │ + │ │ │ │ │ (pure SSA) │ │ │ Wasm ops │ │ + │ └──────────────┘ │ ├──────────────────┤ │ │ │ │ + │ │ │ Optimizer │ │ └──────────────────────┘ │ + │ ┌──────────────┐ │ │ pre + post phase │ │ ▲ │ + │ │ herkos-tests │ │ ├──────────────────┤ │ │ depends on │ + │ │ │ │ │ Phi Lowering │ │ │ │ + │ │ WAT/C/Rust │ │ ├──────────────────┤ │ │ │ + │ │ → .wasm │ │ │ Backend (safe) │ │ │ │ + │ │ → transpile │ │ ├──────────────────┤ │ │ │ + │ │ → test │◄─┤ │ Codegen │ ├───────────┘ │ + │ │ │ │ └──────────────────┘ │ │ + │ │ benches/ │ │ │ │ + │ └──────────────┘ └────────────────────────┘ │ + └───────────────────────────────────────────────────────────────────────────┘ + +Runtime (``herkos-runtime``) +---------------------------- + +*Source:* ``crates/herkos-runtime/src/`` + +The runtime is a ``#![no_std]`` crate providing the types that all transpiled code depends on. It has **zero external dependencies** in the default configuration. + +.. list-table:: + :header-rows: 1 + + * - Module + - Provides + - Reference + * - ``memory.rs`` + - ``IsolatedMemory``, load/store methods, ``memory.grow``/``memory.size`` + - §2.1 + * - ``table.rs`` + - ``Table``, ``FuncRef`` + - §2.3 + * - ``module.rs`` + - ``Module``, ``LibraryModule`` + - §2.2 + * - ``ops.rs`` + - Wasm arithmetic operations (``i32_div_s``, ``i32_trunc_f32_s``, etc.) + - §4.4 + * - ``lib.rs`` + - ``WasmTrap``, ``WasmResult``, ``ConstructionError``, ``PAGE_SIZE`` + - §4.3 + +**Constraints** (see :doc:`/REQUIREMENTS`): + +- No heap allocation without the optional ``alloc`` feature gate +- No panics, no ``format!``, no ``String`` +- Errors are ``Result`` only +- Optional ``alloc`` feature gate for targets with a global allocator + +**Runtime verification with Kani**: The runtime includes ``#[kani::proof]`` harnesses that verify core invariants (no panics on any input, correct grow semantics, load/store roundtrip). Run via ``cargo kani``. See ``crates/herkos-runtime/KANI.md`` in the repository root. + +Transpiler (``herkos-core``) +---------------------------- + +*Source:* ``crates/herkos-core/src/`` + +``herkos-core`` is the transpiler library. The ``herkos`` crate is a thin CLI wrapper around it. The pipeline: + +.. code-block:: text + + herkos-core::transpile() + ┌──────────────────────────────────────────────────────────────────────┐ + │ │ + │ .wasm ──→ Parser ──→ IR Builder ──→ optimize_ir() ──→ lower_phis(). │ + │ │ │ │ │ │ + │ │ wasmparser │ pure SSA IR │ pre-lowering │ SSA │ + │ │ crate │ phi nodes │ passes │ destruct│ + │ ▼ ▼ ▼ ▼ │ + │ ParsedModule ModuleInfo ModuleInfo LoweredModule │ + │ + IrFunctions (optimized) Info │ + │ │ │ + │ ──→ optimize_lowered_ir() ──→ Codegen ──→ rustfmt │ │ + │ │ │ │ │ │ + │ │ post-lowering │ Backend │ format │ │ + │ │ passes │ (safe) │ │ │ + │ ▼ ▼ ▼ │ │ + │ LoweredModuleInfo String String ◄───┘ │ + │ (re-optimized) (raw) (formatted) │ + └──────────────────────────────────────────────────────────────────────┘ + +Parser +~~~~~~ + +*Source:* ``crates/herkos-core/src/parser/`` + +Uses the ``wasmparser`` crate to extract module structure: types, functions, memories, tables, globals, imports, exports, data segments, element segments. + +**Design choice**: ``wasmparser`` only, not ``wasm-tools`` or ``walrus``. Keeps the dependency tree small and avoids pulling in a full Wasm runtime. + +IR (Intermediate Representation) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*Source:* ``crates/herkos-core/src/ir/`` + +A pure SSA-form IR that sits between Wasm bytecode and Rust source. Every variable is defined exactly once (``DefVar`` token, non-``Copy``) and may be read many times (``UseVar`` token, ``Copy``). + +.. code-block:: text + + Wasm bytecode SSA IR Rust source + ┌──────────────────────┐ ┌──────────────────────────┐ ┌──────────────────────────┐ + │ i32.const 5 │ │ v0 = Const(I32(5)) │ │ let mut v0: i32 = 0i32; │ + │ i32.const 3 │ │ v1 = Const(I32(3)) │ │ let mut v1: i32 = 0i32; │ + │ i32.add │ │ v2 = BinOp(Add, v0, v1) │ │ let mut v2: i32 = 0i32; │ + │ │ │ │ │ v0 = 5i32; │ + │ │ │ │ │ v1 = 3i32; │ + │ │ │ │ │ v2 = v0.wrapping_add(v1);│ + └──────────────────────┘ └──────────────────────────┘ └──────────────────────────┘ + +Key types (defined in ``ir/types.rs``): + +- ``ModuleInfo`` — complete module metadata (types, functions, memories, globals, imports, exports) +- ``LoweredModuleInfo`` — newtype wrapper around ``ModuleInfo`` guaranteeing no ``IrInstr::Phi`` nodes remain; only produced by ``lower_phis::lower()`` +- ``IrFunction`` — one function's IR: entry block, all basic blocks, locals, return type, type index +- ``IrBlock`` — basic block with a ``Vec`` body and an ``IrTerminator`` +- ``IrInstr`` — a single SSA instruction: ``Const``, ``BinOp``, ``UnOp``, ``Load``, ``Store``, ``Call``, ``CallImport``, ``CallIndirect``, ``Assign``, ``GlobalGet``, ``GlobalSet``, ``MemorySize``, ``MemoryGrow``, ``MemoryCopy``, ``MemoryFill``, ``MemoryInit``, ``DataDrop``, ``Select``, ``Phi`` +- ``IrTerminator`` — block exit: ``Return``, ``Jump``, ``BranchIf``, ``BranchTable``, ``Unreachable`` +- ``VarId`` — SSA variable identifier (displayed as ``v0``, ``v1``, ...) +- ``BlockId`` — basic block identifier (displayed as ``block_0``, ``block_1``, ...) +- ``DefVar`` / ``UseVar`` — single-use definition / multi-use read tokens enforcing SSA invariants at build time + +Index types use a phantom-typed ``Idx`` generic to prevent mixing ``LocalFuncIdx``, ``ImportIdx``, ``GlobalIdx``, ``TypeIdx``, etc. + +The builder (``ir/builder/``) translates Wasm stack-based instructions to SSA IR by maintaining an explicit value stack of ``UseVar``. Each function is independent — enabling future parallelization (see §6.2). + +SSA Phi Lowering +~~~~~~~~~~~~~~~~ + +*Source:* ``crates/herkos-core/src/ir/lower_phis.rs`` + +SSA phi nodes are inserted by the builder at join points (if/else merges, loop headers). Before codegen they must be *destroyed* — converted to ordinary assignments in predecessor blocks. + +.. code-block:: text + + Before lowering (SSA IR): After lowering (LoweredModuleInfo): + + block0: block0: + br_if cond → block1, block2 br_if cond → block1, block2 + + block1 (then): block1 (then): + br → block3 v2 = v0 ← Assign inserted + br → block3 + + block2 (else): block2 (else): + br → block3 v2 = v1 ← Assign inserted + br → block3 + + block3 (merge): block3 (merge): + v2 = Phi(block1→v0, block2→v1) (Phi removed) + +The pass: + +1. **Prunes stale sources**: removes ``(pred, var)`` entries whose predecessor was eliminated by dead block removal +2. **Simplifies trivial phis**: single-source or all-same-source phis become ``Assign`` in-place +3. **Lowers non-trivial phis**: inserts ``Assign { dest, src }`` at the end of each predecessor block, then removes the ``Phi`` + +Optimizer +~~~~~~~~~ + +*Source:* ``crates/herkos-core/src/optimizer/`` + +The optimizer is split into two phases separated by phi lowering: + +**Pre-lowering passes** (operate on SSA IR with phi nodes intact): + +.. list-table:: + :header-rows: 1 + + * - Pass + - What it does + * - ``dead_blocks`` + - Removes basic blocks unreachable from the entry block + * - ``const_prop`` + - Propagates constant values through assignments and binary ops + * - ``algebraic`` + - Algebraic simplifications (e.g., ``x + 0 → x``, ``x * 1 → x``) + * - ``copy_prop`` + - Replaces uses of copy vars with their sources (``v1 = v0; use(v1)`` → ``use(v0)``) + +**Post-lowering passes** (operate on phi-free ``LoweredModuleInfo``): + +.. list-table:: + :header-rows: 1 + + * - Pass + - What it does + * - ``empty_blocks`` + - Removes blocks with no instructions and a single unconditional jump + * - ``dead_blocks`` + - Second dead block pass after structural changes + * - ``merge_blocks`` + - Merges a block with its sole successor when no other predecessor exists + * - ``copy_prop`` + - Copy propagation on lowered IR + * - ``local_cse`` + - Local common subexpression elimination within each block + * - ``gvn`` + - Global value numbering across blocks + * - ``dead_instrs`` + - Removes instructions whose results are never used + * - ``branch_fold`` + - Folds constant-condition branches (``br_if true → jump``) + * - ``licm`` + - Loop-invariant code motion: hoists invariant computations out of loops + +Both phases run up to 2 iterations until fixed point. Passes run only when ``--optimize`` / ``-O`` is passed. + +Backend +~~~~~~~ + +*Source:* ``crates/herkos-core/src/backend/`` + +The ``Backend`` trait abstracts the code emission strategy. Currently only ``SafeBackend`` is implemented: + +- Emits 100% safe Rust +- Every memory access goes through bounds-checked wrappers returning ``WasmResult`` +- No verification metadata required + +For the planned verified and hybrid backends, see :doc:`/FUTURE`. + +Code Generator +~~~~~~~~~~~~~~ + +*Source:* ``crates/herkos-core/src/codegen/`` + +Walks the ``LoweredModuleInfo`` and emits Rust source code via the configured ``Backend``: + +.. list-table:: + :header-rows: 1 + + * - Codegen module + - Responsibility + * - ``module.rs`` + - Top-level orchestration; module struct definition + * - ``function.rs`` + - Function signatures, local declarations, block state machines + * - ``instruction.rs`` + - Individual ``IrInstr`` → Rust expression + * - ``traits.rs`` + - ``ModuleHostTrait`` generation from function imports + * - ``export.rs`` + - Export method generation (forwarding to internal functions) + * - ``constructor.rs`` + - ``new()`` with data segment and element segment initialization + * - ``env.rs`` + - ``Env`` context struct bundling host + globals + * - ``types.rs`` + - Wasm → Rust type name mapping + * - ``utils.rs`` + - Call arg building, import grouping + +**Multi-block control flow** uses a local ``Block`` enum and a ``loop { match __block { … } }`` state machine. Single-block functions optimize to flat inline code. + +Tests (``herkos-tests``) +------------------------ + +*Source:* ``crates/herkos-tests/`` + +End-to-end test crate that compiles WAT/C/Rust sources to ``.wasm``, transpiles them, and runs the output. + +Test pipeline +~~~~~~~~~~~~~ + +.. code-block:: text + + WAT / C / Rust source + │ + ▼ (build.rs) + .wasm binary + │ + ▼ (herkos::transpile) + Generated .rs + │ + ▼ (include! in test) + Compiled & tested + +Test categories +~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Category + - Test files + - What's tested + * - Arithmetic + - ``arithmetic.rs``, ``numeric_ops.rs`` + - Wasm arithmetic, bitwise, comparison ops + * - Memory + - ``memory.rs``, ``memory_grow.rs``, ``subwidth_mem.rs``, ``bulk_memory.rs`` + - Load/store, memory.grow, sub-width access, memory.copy/fill/init + * - Control flow + - ``control_flow.rs``, ``early_return.rs``, ``select.rs``, ``unreachable.rs`` + - Block, loop, if, br, br_table, select + * - Functions + - ``function_calls.rs``, ``indirect_calls.rs``, ``indirect_call_import.rs`` + - Direct calls, call_indirect dispatch, indirect calls through imports + * - Imports/Exports + - ``import_traits.rs``, ``import_memory.rs``, ``import_multi.rs``, ``module_wrapper.rs``, ``call_import_transitive.rs`` + - Trait-based imports, module wrapper, transitive import calls + * - Locals + - ``locals.rs``, ``locals_aliasing.rs`` + - Local variable handling + * - Inter-module + - ``inter_module_lending.rs`` + - Memory lending between modules + * - E2E (C) + - ``c_e2e.rs``, ``c_e2e_i64.rs``, ``c_e2e_loops.rs``, ``c_e2e_memory.rs`` + - Full C → Wasm → Rust pipeline + * - E2E (Rust) + - ``rust_e2e.rs``, ``rust_e2e_control.rs``, ``rust_e2e_i64.rs``, ``rust_e2e_heavy_fibo.rs``, ``rust_e2e_memory_bench.rs`` + - Pre-generated Rust modules + +Running tests +~~~~~~~~~~~~~ + +.. code-block:: bash + + cargo test -p herkos-core # transpiler unit tests (IR, optimizer, codegen) + cargo test -p herkos-runtime # runtime unit tests + + # herkos-tests must always be run twice: + HERKOS_OPTIMIZE=0 cargo test -p herkos-tests # unoptimized transpiler output + HERKOS_OPTIMIZE=1 cargo test -p herkos-tests # optimized transpiler output + +``HERKOS_OPTIMIZE`` is read by ``herkos-tests/build.rs`` at compile time. When set to ``"1"``, the test suite's ``.wasm`` sources are transpiled with the IR optimization pipeline enabled; any other value (or unset) disables it. Running both variants is required — it verifies that the optimizer is *semantics-preserving*: the same inputs must produce the same outputs regardless of optimization level. CI enforces both runs as separate steps. The variable has no effect on ``herkos-core``, ``herkos-runtime``, or any production code. + +Benchmarks +---------- + +*Source:* ``crates/herkos-tests/benches/`` + +Performance benchmarks using Criterion. Currently includes Fibonacci benchmarks comparing transpiled Wasm execution against native Rust. + +.. code-block:: bash + + cargo bench -p herkos-tests diff --git a/docs/specification/index.rst b/docs/specification/index.rst new file mode 100644 index 0000000..87f8f7c --- /dev/null +++ b/docs/specification/index.rst @@ -0,0 +1,24 @@ +.. _specification: + +Specification +============= + +This document specifies the design and behavior of the herkos transpilation pipeline. It takes the goals and constraints defined in :doc:`/REQUIREMENTS` as input and describes **how** they are achieved. + +Where the requirements say *what* the system must do, this specification says *how* it does it. + +For features that are planned but not yet implemented (verified/hybrid backends, temporal isolation, etc.), see :doc:`/FUTURE`. + +**Document Status**: Draft — Version 0.3 — 2026-04-12 + +.. toctree:: + :maxdepth: 2 + + module_representation + architecture + transpilation_rules + integration + performance + security_properties + open_questions + references diff --git a/docs/specification/integration.rst b/docs/specification/integration.rst new file mode 100644 index 0000000..b26a248 --- /dev/null +++ b/docs/specification/integration.rst @@ -0,0 +1,105 @@ +.. _integration: + +Integration +=========== + +Trait-Based Integration (Primary) +--------------------------------- + +The host instantiates modules and provides capabilities through trait implementations: + +.. code-block:: rust + + struct MyHost { /* platform resources */ } + impl SocketOps for MyHost { /* ... */ } + impl WasiFd for MyHost { /* ... */ } + + let mut module = Module::::new(16, MyGlobals::default(), table)?; + let mut host = MyHost::new(); + let result = module.process_data(&mut host, ptr, len)?; + +Full type safety, zero ``unsafe``, zero-cost dispatch via monomorphization. + +The ``Env`` Context Pattern +------------------------------ + +*Implementation:* ``crates/herkos-core/src/codegen/env.rs`` + +Generated modules use a unified **Env** context struct that bundles the host (generic parameter ``H``) and mutable globals, simplifying parameter threading throughout function calls. + +.. code-block:: rust + + // Generated by transpiler + pub struct Env<'a, H: ModuleHostTrait + ?Sized> { + pub host: &'a mut H, + pub globals: &'a mut Globals, + } + + // Every function that needs imports or mutable state receives Env + fn process( + memory: &mut IsolatedMemory, + env: &mut Env, + input: i32, + ) -> WasmResult { + // Call imported function via trait + let result = env.host.some_import(input)?; + // Read/write mutable global + env.globals.my_global += 1; + Ok(result) + } + +**Design rationale:** + +- **Unified state**: Avoids threading ``host``, ``globals``, and other mutable state as separate parameters +- **Type safety**: All imports must be present in the host's trait implementation — checked at compile time +- **Zero overhead**: The Env struct is a thin wrapper; LLVM inlines and optimizes away the indirection +- **Extensibility**: Adding new imports or globals requires only modifying the trait, not all function signatures + +**Generated trait:** + +.. code-block:: rust + + pub trait ModuleHostTrait { + // One method per function import + fn imported_function(&mut self, arg: i32) -> WasmResult; + + // Getter/setter methods for each imported global + fn get_imported_global(&self) -> i32; + fn set_imported_global(&mut self, value: i32); + } + +C-Compatible ABI (Optional) +--------------------------- + +For integration with non-Rust systems, an optional ``extern "C"`` wrapper erases generics: + +.. code-block:: rust + + #[no_mangle] + pub extern "C" fn module_new(initial_pages: u32) -> *mut OpaqueModule { /* ... */ } + + #[no_mangle] + pub extern "C" fn module_call( + instance: *mut OpaqueModule, + function_index: u32, + args: *const i64, + args_len: usize, + result: *mut i64, + ) -> i32 { /* 0 = success, non-zero = WasmTrap discriminant */ } + +The C ABI wrapper uses ``unsafe`` and raw pointers. Capability enforcement still applies inside — the wrapper calls through trait-bounded functions. This is an escape hatch, not the default. + +Native Rust Integration +----------------------- + +Native Rust code integrates by implementing import traits directly: + +.. code-block:: rust + + trait GpioOps { + fn gpio_set(&mut self, pin: u32, value: bool) -> WasmResult<()>; + fn gpio_read(&self, pin: u32) -> WasmResult; + } + + struct EmbeddedHost { /* ... */ } + impl GpioOps for EmbeddedHost { /* ... */ } diff --git a/docs/specification/module_representation.rst b/docs/specification/module_representation.rst new file mode 100644 index 0000000..77c9c99 --- /dev/null +++ b/docs/specification/module_representation.rst @@ -0,0 +1,415 @@ +.. _module-representation: + +Module Representation +===================== + +This section describes how WebAssembly concepts map to Rust types. This is the core abstraction layer — everything else (transpilation, integration, performance) builds on these types. + +Memory Model +------------ + +.. spec:: Memory Model + :id: SPEC_MEMORY_MODEL + :satisfies: REQ_MEM_PAGE_MODEL, REQ_MEM_COMPILE_TIME_SIZE, REQ_MEM_BOUNDS_CHECKED, REQ_MEM_GROW_NO_ALLOC + :tags: memory + + How WebAssembly linear memory maps to ``IsolatedMemory`` in Rust. + +Page Model +~~~~~~~~~~ + +WebAssembly linear memory is organized in pages of 64 KiB (65,536 bytes). A Wasm module declares an initial page count and an optional maximum page count. + +.. code-block:: text + + Page size: 64 KiB (defined by the WebAssembly specification) + Initial size: declared in the Wasm module (e.g., 16 pages = 1 MiB) + Maximum size: declared in the Wasm module (e.g., 256 pages = 16 MiB) + +Rust Representation: ``IsolatedMemory`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*Implementation:* ``crates/herkos-runtime/src/memory.rs`` + +.. code-block:: rust + + const PAGE_SIZE: usize = 65536; + + struct IsolatedMemory { + pages: [[u8; PAGE_SIZE]; MAX_PAGES], + active_pages: usize, + } + +**Design decisions**: + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Decision + - Rationale + * - ``MAX_PAGES`` const generic + - No heap allocation, ``no_std`` compatible, enables monomorphization + * - ``active_pages`` runtime tracking + - Starts at initial page count, grows via ``memory.grow``, bounds-checks against this + * - 2D array ``[[u8; PAGE_SIZE]; MAX_PAGES]`` + - Avoids unstable ``generic_const_exprs``. ``as_flattened()`` provides flat ``&[u8]`` views (stable Rust 1.80+) + * - No maximum → CLI configurable + - If the Wasm module declares no maximum, the transpiler picks a default (configurable via ``--max-pages``) + +Memory Access API +~~~~~~~~~~~~~~~~~ + +All memory operations are flat — no ``MemoryView`` wrappers. One method per Wasm type, avoiding monomorphization of inner functions: + +.. code-block:: rust + + impl IsolatedMemory { + // Safe: bounds-checked against active_pages * PAGE_SIZE + fn load_i32(&self, offset: usize) -> WasmResult; + fn load_i64(&self, offset: usize) -> WasmResult; + fn load_u8(&self, offset: usize) -> WasmResult; + fn load_u16(&self, offset: usize) -> WasmResult; + fn load_f32(&self, offset: usize) -> WasmResult; + fn load_f64(&self, offset: usize) -> WasmResult; + fn store_i32(&mut self, offset: usize, value: i32) -> WasmResult<()>; + fn store_i64(&mut self, offset: usize, value: i64) -> WasmResult<()>; + // ... and store_u8, store_u16, store_f32, store_f64 + } + +Read-only guarantees are not a Wasm primitive — they are an analysis result. Static analysis can prove that certain regions (e.g., ``.rodata`` data segments) are never targeted by store instructions. This is relevant to the future verified backend (see :doc:`/FUTURE`). + +``memory.grow`` Semantics +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: rust + + impl IsolatedMemory { + fn grow(&mut self, delta: u32) -> i32 { + let old = self.active_pages; + let new = old.wrapping_add(delta as usize); + if new > MAX_PAGES { + return -1; + } + for page in &mut self.pages[old..new] { + page.fill(0); + } + self.active_pages = new; + old as i32 + } + } + +No allocation occurs. New pages are zero-initialized per the Wasm spec. + +Linear Memory Layout +~~~~~~~~~~~~~~~~~~~~ + +When C/C++ compiles to Wasm, the compiler organizes linear memory into conventional regions: + +.. code-block:: text + + ┌─────────────────────────────────────────┐ MAX_PAGES * PAGE_SIZE + │ (unused / growable) │ + ├─────────────────────────────────────────┤ ← __stack_pointer (grows ↓) + │ Shadow Stack │ + │ (local variables, large structs, │ + │ spills, return values) │ + ├─────────────────────────────────────────┤ + │ Heap (grows ↑) │ + │ (malloc / C++ new) │ + ├─────────────────────────────────────────┤ + │ Data Segments │ + │ (.data, .rodata, .bss) │ + └─────────────────────────────────────────┘ 0 + +Key points: + +- Wasm's value stack only holds scalars (i32, i64, f32, f64). Large structs and address-taken locals live in the **shadow stack** in linear memory. +- A "pure" C function returning a large struct actually writes to its shadow stack frame via ``i32.store`` instructions — not pure with respect to memory. + +Compile-Time Guarantees +~~~~~~~~~~~~~~~~~~~~~~~ + +- **Spatial safety**: all memory accesses bounds-checked against ``active_pages * PAGE_SIZE`` +- **Temporal safety**: Rust's lifetime system prevents use-after-free +- **Isolation**: each module has its own ``IsolatedMemory`` instance — distinct types, distinct backing arrays, no cross-module access possible + +Module Types +------------ + +.. spec:: Module Types + :id: SPEC_MODULE_TYPES + :satisfies: REQ_MOD_TWO_TYPES + :tags: module + + Process-like (owns memory) and library-like (borrows memory) module representations. + +*Implementation:* ``crates/herkos-runtime/src/module.rs`` + +.. code-block:: text + + ┌─────────────────────────────────────┐ + │ Module Taxonomy │ + ├──────────────────┬──────────────────┤ + │ │ │ + ┌─────┴───-──┐ ┌──────┴──────┐ ┌───-───┴─────┐ + │ Module │ │ Library │ │ Pure │ + │ (owns mem) │ │ Module │ │ (no memory) │ + │ │ │ (borrows) │ │ │ + └────────────┘ └─────────────┘ └─────────────┘ + Like a process Like a shared Pure computation + library + +Process-like Module (owns memory) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: rust + + struct Module { + memory: IsolatedMemory, + globals: G, + table: Table, + } + +Library Module (borrows memory) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: rust + + struct LibraryModule { + globals: G, + table: Table, + // no memory field — uses caller's memory + } + +.. list-table:: + :header-rows: 1 + + * - Wasm declaration + - Rust representation + - Analogy + * - Module defines memory + - ``Module`` owns ``IsolatedMemory`` + - POSIX process + * - Module imports memory + - ``LibraryModule`` borrows ``&mut IsolatedMemory`` + - Shared library + * - Module has no memory + - ``LibraryModule`` with no memory parameter + - Pure computation + +Globals and Tables +------------------ + +.. spec:: Globals and Tables + :id: SPEC_GLOBALS_TABLES + :satisfies: REQ_MOD_GLOBALS, REQ_MOD_TABLE + :tags: module, global, table + + Globals as typed struct fields, tables for indirect call dispatch. + +*Implementation:* ``crates/herkos-runtime/src/table.rs`` + +Globals +~~~~~~~ + +.. code-block:: rust + + // Generated by the transpiler — one struct per module + struct Globals { + g0: i32, // (global (mut i32) ...) — mutable, lives in struct + // g1 is immutable → emitted as `const G1: i64 = 42;` instead + } + +Tables +~~~~~~ + +.. code-block:: rust + + struct Table { + entries: [Option; MAX_SIZE], + active_size: usize, + } + + struct FuncRef { + type_index: u32, // canonical type index for signature check + func_index: u32, // index into module function space → match dispatch + } + +Tables are initialized from element segments during module construction: + +.. code-block:: rust + + // From: (elem (i32.const 0) $add $sub $mul) + let mut table = Table::try_new(3); + table.set(0, Some(FuncRef { type_index: 0, func_index: 0 })).unwrap(); + table.set(1, Some(FuncRef { type_index: 0, func_index: 1 })).unwrap(); + table.set(2, Some(FuncRef { type_index: 0, func_index: 2 })).unwrap(); + +Imports as Trait Bounds +----------------------- + +.. spec:: Imports as Trait Bounds + :id: SPEC_IMPORTS + :satisfies: REQ_CAP_IMPORTS, REQ_CAP_ZERO_COST + :tags: capability, import + + Wasm imports mapped to Rust trait bounds for capability-based security. + +Capabilities are Rust **traits**, not bitflags. A Wasm module's imports become trait bounds on its functions: + +.. code-block:: rust + + // Generated from: (import "env" "socket_open" (func ...)) + // (import "env" "socket_read" (func ...)) + trait SocketOps { + fn socket_open(&mut self, domain: i32, sock_type: i32) -> WasmResult; + fn socket_read(&mut self, fd: i32, buf_ptr: u32, len: u32) -> WasmResult; + } + + // Module function that calls socket imports requires the trait: + fn send_data( + host: &mut H, + memory: &mut IsolatedMemory, + // ... + ) -> WasmResult { + let sock = host.socket_open(2, 1)?; + // ... + } + + // No imports → no host parameter, pure computation: + fn pure_math(a: i32, b: i32) -> i32 { a.wrapping_add(b) } + +.. list-table:: + :header-rows: 1 + + * - Aspect + - Bitflags (``const CAPS: u64``) + - Traits + * - Granularity + - Coarse (1 bit = 1 class) + - Fine (exact function signatures) + * - Compile-time checking + - Fails if bit not set + - Fails if trait not implemented + * - Error messages + - Opaque bit mismatch + - Clear: "trait ``SocketOps`` not implemented" + * - Runtime cost + - Zero + - Zero (monomorphization) + * - Extensibility + - Limited to 64 bits + - Unlimited + * - Inter-module linking + - Not supported + - Natural via trait composition + +Exports as Trait Implementations +-------------------------------- + +.. spec:: Exports as Trait Implementations + :id: SPEC_EXPORTS + :satisfies: REQ_CAP_EXPORTS, REQ_CAP_ZERO_COST + :tags: capability, export + + Wasm exports mapped to Rust trait implementations. + +.. code-block:: rust + + // Generated from: (export "transform" (func $transform)) + trait ImageLibExports { + fn transform(&mut self, ptr: u32, len: u32) -> WasmResult; + fn init(&mut self) -> WasmResult<()>; + } + + impl ImageLibExports for ImageModule { + fn transform(&mut self, ptr: u32, len: u32) -> WasmResult { + func_transform(&mut self.memory, &mut self.globals, ptr, len) + } + fn init(&mut self) -> WasmResult<()> { + func_init(&mut self.memory, &mut self.globals) + } + } + +WASI Support +------------ + +WASI is a standard set of import traits shipped by ``herkos-runtime``: + +.. code-block:: rust + + trait WasiFd { + fn fd_read(&mut self, fd: i32, iovs: u32, iovs_len: u32, nread: u32) -> WasmResult; + fn fd_write(&mut self, fd: i32, iovs: u32, iovs_len: u32, nwritten: u32) -> WasmResult; + fn fd_close(&mut self, fd: i32) -> WasmResult; + // ... + } + + trait WasiClock { + fn clock_time_get(&mut self, clock_id: i32, precision: i64, time: u32) -> WasmResult; + } + + trait WasiRandom { + fn random_get(&mut self, buf: u32, len: u32) -> WasmResult; + } + +The host implements whichever subset it supports: + +.. code-block:: rust + + // Bare-metal: only fd_write (UART) and clock + struct EmbeddedHost { /* ... */ } + impl WasiFd for EmbeddedHost { /* UART-backed */ } + impl WasiClock for EmbeddedHost { /* hardware timer */ } + + // Full POSIX: everything + struct PosixHost { /* ... */ } + impl WasiFd for PosixHost { /* real file ops */ } + impl WasiClock for PosixHost { /* clock_gettime */ } + impl WasiRandom for PosixHost { /* /dev/urandom */ } + +Custom platform-specific capabilities beyond WASI are just additional traits (e.g., ``GpioOps``, ``CanBusOps``). + +Isolation Guarantees +-------------------- + +.. spec:: Isolation Guarantees + :id: SPEC_ISOLATION + :satisfies: REQ_ISOLATION_COMPILE_TIME, REQ_FREEDOM_FROM_INTERFERENCE, REQ_ISOLATION_SPATIAL, REQ_ISOLATION_CAPABILITY + :tags: isolation, safety + + Compile-time freedom from interference via Rust ownership model. + +The ownership model enforces freedom from interference structurally: + +.. code-block:: text + + ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ + │ Module A │ │ Module B │ │ Library C │ + │ │ │ │ │ │ + │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ (no memory) │ + │ │ Memory A │ │ │ │ Memory B │ │ │ │ + │ │ (owned) │ │ │ │ (owned) │ │ │ Borrows caller │ + │ └─────────────┘ │ │ └─────────────┘ │ │ memory for │ + │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ duration of │ + │ │ Globals A │ │ │ │ Globals B │ │ │ each call │ + │ └─────────────┘ │ │ └─────────────┘ │ │ │ + └─────────────────┘ └─────────────────┘ └─────────────────┘ + ✗ cannot ✗ cannot ✓ borrows + access B access A one at a time + +1. **Module with its own memory**: cannot access another module's memory — each owns a distinct ``IsolatedMemory`` instance +2. **Library module**: can only access the specific memory it was handed via ``&mut`` borrow. Cannot hold the reference past the call (lifetime enforced), cannot access a different module's memory +3. **Pure module**: no memory at all — the type system provides no memory access methods + +Inter-module calls lend memory for the duration of the call: + +.. code-block:: rust + + let mut app = Module::::new(16, AppGlobals::default(), table)?; + let mut lib = LibraryModule::::new(LibGlobals::default(), table)?; + + // Caller's memory is borrowed for this call only. + // Rust borrow checker guarantees the library cannot store the reference. + let result = lib.call_export_transform(&mut app.memory, ptr, len)?; diff --git a/docs/specification/open_questions.rst b/docs/specification/open_questions.rst new file mode 100644 index 0000000..df83cdd --- /dev/null +++ b/docs/specification/open_questions.rst @@ -0,0 +1,9 @@ +.. _open-questions: + +Open Questions +============== + +1. How to handle C++ exceptions in WebAssembly? +2. How to represent and verify concurrent access patterns? +3. Should we support dynamic linking of transpiled modules? +4. What level of C/C++ standard library should be supported? diff --git a/docs/specification/performance.rst b/docs/specification/performance.rst new file mode 100644 index 0000000..7f12674 --- /dev/null +++ b/docs/specification/performance.rst @@ -0,0 +1,129 @@ +.. _performance: + +Performance +=========== + +Overhead +-------- + +.. list-table:: + :header-rows: 1 + + * - Backend + - Overhead + - Source + - Status + * - Safe + - 15–30% + - Runtime bounds check on every memory access + - Implemented + * - Verified + - 0–5% + - Function call indirection only + - Planned (:doc:`/FUTURE`) + * - Hybrid + - 5–15% + - Mix of checked and proven accesses + - Planned (:doc:`/FUTURE`) + +Monomorphization Bloat Mitigation +--------------------------------- + +Each distinct ``MAX_PAGES`` and trait bound combination generates separate code. Mitigation strategies: + +Outline pattern (mandatory for runtime) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Move logic into non-generic inner functions. Generic wrapper is a thin shell: + +.. code-block:: rust + + #[inline(never)] + fn load_i32_inner(memory: &[u8], active_bytes: usize, offset: usize) -> WasmResult { + // ONE copy in the binary + } + + impl IsolatedMemory { + #[inline(always)] + fn load_i32(&self, offset: usize) -> WasmResult { + load_i32_inner(self.pages.as_flattened(), self.active_pages * PAGE_SIZE, offset) + } + } + +``MAX_PAGES`` normalization +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use standard sizes (16, 64, 256, 1024) instead of exact declared maximums. Two modules with ``MAX_PAGES=253`` and ``MAX_PAGES=260`` both use ``MAX_PAGES=256``. + +Trait objects for cold paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use ``&mut dyn Trait`` instead of generics for rarely-called code (error handling, initialization). + +LTO +~~~ + +Link-time optimization eliminates unreachable monomorphized copies. + +Transpiler Parallelization +-------------------------- + +IR building and code generation are embarrassingly parallel — each function is independent: + +.. code-block:: text + + ┌──────────┐ + │ Parse │ (sequential) + └────┬─────┘ + │ + ┌─────────────┼───────────┐ + ▼ ▼ ▼ + ┌──────────┐ ┌──────────┐ ┌──────────┐ + │ IR Build │ │ IR Build │ │ IR Build │ (parallel) + │ func_0 │ │ func_1 │ │ func_N │ + └────┬─────┘ └────┬─────┘ └────┬─────┘ + │ │ │ + ▼ ▼ ▼ + ┌──────────┐ ┌──────────┐ ┌──────────┐ + │ Codegen │ │ Codegen │ │ Codegen │ (parallel) + │ func_0 │ │ func_1 │ │ func_N │ + └────┬─────┘ └────┬─────┘ └────┬─────┘ + │ │ │ + └────────────┼────────────┘ + ▼ + ┌──────────┐ + │ Assemble │ (sequential) + └──────────┘ + +Activation heuristic: use ``rayon`` parallel iterators when the module has 20+ functions. Output is deterministic regardless of thread count (``par_iter().enumerate()`` preserves order). + +Comparison to Alternatives +-------------------------- + +.. list-table:: + :header-rows: 1 + + * - Approach + - Runtime Overhead + - Isolation Strength + - ``unsafe`` in output + * - MMU/MPU + - 10–50% (context switches) + - Strong (hardware) + - N/A + * - herkos (safe) + - 15–30% + - Strong (runtime checks) + - None + * - herkos (verified, planned) + - 0–5% + - Strong (formal proofs) + - Yes — proof-justified + * - WebAssembly runtime + - 20–100% + - Strong (runtime sandbox) + - N/A + * - Software fault isolation + - 10–30% + - Medium (runtime) + - N/A diff --git a/docs/specification/references.rst b/docs/specification/references.rst new file mode 100644 index 0000000..3e34a1e --- /dev/null +++ b/docs/specification/references.rst @@ -0,0 +1,9 @@ +.. _references: + +References +========== + +- WebAssembly Specification: https://webassembly.github.io/spec/ +- Rust Reference: https://doc.rust-lang.org/reference/ +- Software Fault Isolation: Wahbe et al., 1993 +- Proof-Carrying Code: Necula & Lee, 1996 diff --git a/docs/specification/security_properties.rst b/docs/specification/security_properties.rst new file mode 100644 index 0000000..de7fcb1 --- /dev/null +++ b/docs/specification/security_properties.rst @@ -0,0 +1,29 @@ +.. _security-properties: + +Security Properties +=================== + +Protected Against +----------------- + +- **Memory corruption**: buffer overflows, use-after-free — prevented by bounds-checked access and Rust's ownership system +- **Unauthorized resource access**: files, network, system calls — prevented by trait-based capability enforcement +- **Cross-module interference**: freedom from interference — enforced by memory ownership isolation +- **ROP attacks**: no function pointers in generated code — all dispatch is static match + +Not Protected Against (current scope) +------------------------------------- + +- Logic bugs in the original C/C++ code +- Side-channel attacks (timing, cache) +- Resource exhaustion (infinite loops, memory leaks within bounds) — see :doc:`/FUTURE` §3 for temporal isolation plans +- Timing interference — spatial isolation only, not temporal + +Relationship to Safety Standards +-------------------------------- + +This pipeline produces **evidence** for a freedom-from-interference argument: + +- Transpiled Rust source is auditable +- Isolation boundary is the Rust type system — well-understood, no runtime configuration dependency +- **This tool does not replace a formal safety case.** It provides a compile-time isolation mechanism and associated evidence that can be used as part of one. diff --git a/docs/specification/transpilation_rules.rst b/docs/specification/transpilation_rules.rst new file mode 100644 index 0000000..3e6e6d2 --- /dev/null +++ b/docs/specification/transpilation_rules.rst @@ -0,0 +1,274 @@ +.. _transpilation-rules: + +Transpilation Rules +=================== + +This section describes how Wasm constructs map to Rust code in the safe backend. + +Function Translation +-------------------- + +.. spec:: Function Translation + :id: SPEC_FUNCTION_TRANSLATION + :satisfies: REQ_TRANS_FUNCTIONS, REQ_TRANS_DETERMINISTIC + :tags: transpilation, function + + Wasm functions to Rust functions via SSA IR. + +Wasm functions become Rust functions. Module state is threaded through as parameters. Functions that call imports or touch mutable globals receive an ``Env`` context struct; pure computation functions omit it. + +.. code-block:: rust + + // Wasm: (func $example (param i32) (result i32)) + // No imports, no mutable globals → memory only + fn func_0( + memory: &mut IsolatedMemory, + v0: i32, + ) -> WasmResult { + // function body in SSA variable form + } + + // Wasm: (func $send (param i32 i32) (result i32)) + // Calls imported functions + uses mutable globals → Env parameter + fn func_1( + memory: &mut IsolatedMemory, + env: &mut Env, + v0: i32, + v1: i32, + ) -> WasmResult { + // env.host.some_import(...) + // env.globals.g0 = ... + } + +Only state that the function actually uses is passed. Memory is omitted for memory-free functions; ``env`` is omitted when there are no imports and no mutable globals. + +Control Flow +------------ + +.. spec:: Control Flow Mapping + :id: SPEC_CONTROL_FLOW + :satisfies: REQ_TRANS_CONTROL_FLOW + :tags: transpilation, control + + Wasm structured control flow mapped to safe Rust (loop/break/if). + +Wasm structured control flow is lowered to basic blocks in the IR, then emitted as a state-machine loop in Rust: + +.. code-block:: rust + + // Multi-block function body (any branching control flow): + #[derive(Clone, Copy)] + enum __Block { B0, B1, B2 } + let mut __block = __Block::B0; + loop { + match __block { + __Block::B0 => { /* block_0 instructions */; __block = __Block::B1; } + __Block::B1 => { /* block_1 instructions */; if cond { __block = __Block::B2; } else { __block = __Block::B0; } } + __Block::B2 => { return Ok(v_result); } + } + } + +.. list-table:: + :header-rows: 1 + + * - Wasm + - IR + - Rust (state machine) + * - ``block`` / ``end`` + - jump to successor block + - ``__block = __Block::BN`` + * - ``loop`` + - back-edge jump to loop header + - ``__block = __Block::BHeader`` + * - ``if / else / end`` + - ``BranchIf { cond, if_true, if_false }`` + - ``if cond { __block = BT } else { __block = BF }`` + * - ``br $label`` + - ``Jump { target }`` + - ``__block = __Block::BN`` + * - ``br_if $label`` + - ``BranchIf`` + - ``if cond { __block = BT } else { __block = BF }`` + * - ``br_table`` + - ``BranchTable { index, targets, default }`` + - ``match index { 0 => __block = B0, … _ => __block = BD }`` + * - ``unreachable`` + - ``Unreachable`` terminator + - ``return Err(WasmTrap::Unreachable)`` + +Single-block functions (no branches) skip the state machine entirely and emit flat inline code. + +Error Handling +-------------- + +.. spec:: Error Handling + :id: SPEC_ERROR_HANDLING + :satisfies: REQ_ERR_TRAPS + :tags: transpilation, error + + Trap-based error handling via WasmTrap/WasmResult. + +*Implementation:* ``crates/herkos-runtime/src/lib.rs`` + +.. code-block:: rust + + enum WasmTrap { + OutOfBounds, // Memory access out of bounds + DivisionByZero, // Integer division by zero + IntegerOverflow, // e.g., i32.trunc_f64_s on out-of-range float + Unreachable, // unreachable instruction executed + IndirectCallTypeMismatch, // call_indirect signature check failed + TableOutOfBounds, // Table access out of bounds + UndefinedElement, // Undefined element in table + } + + type WasmResult = Result; + +No panics, no unwinding. The ``?`` operator propagates traps up the call stack. + +Arithmetic Operations +--------------------- + +.. spec:: Arithmetic Operations + :id: SPEC_ARITHMETIC + :satisfies: REQ_TRANS_FUNCTIONS + :tags: transpilation, arithmetic + + Wasm arithmetic semantics (wrapping, trapping division, IEEE 754 floats). + +*Implementation:* ``crates/herkos-runtime/src/ops.rs`` + +Wasm arithmetic operations that can trap (division, remainder, truncation) return ``WasmResult``: + +.. code-block:: rust + + fn i32_div_s(a: i32, b: i32) -> WasmResult; // traps on /0 or overflow + fn i32_rem_u(a: i32, b: i32) -> WasmResult; // traps on /0 + fn i32_trunc_f32_s(a: f32) -> WasmResult; // traps on out-of-range + +Non-trapping arithmetic uses Rust's wrapping operations (``wrapping_add``, ``wrapping_mul``, etc.) per the Wasm spec. + +Function Calls +-------------- + +.. spec:: Function Calls + :id: SPEC_FUNCTION_CALLS + :satisfies: REQ_TRANS_INDIRECT_CALLS, REQ_TRANS_TYPE_EQUIVALENCE + :tags: transpilation, call + + Direct calls, indirect calls via table, structural type equivalence. + +Direct Calls (``call``) +~~~~~~~~~~~~~~~~~~~~~~~ + +Direct calls transpile to regular Rust function calls with state threaded through: + +.. code-block:: rust + + // Wasm: call $func_3 (with 2 args on the stack) + v5 = func_3(memory, globals, table, v3, v4)?; + +Indirect Calls (``call_indirect``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``call_indirect`` implements function pointers. The transpiler emits a static match dispatch: + +.. code-block:: rust + + // Wasm: call_indirect (type $binop) ; expects (i32, i32) -> i32 + let __entry = table.get(v2 as u32)?; // lookup + bounds check + if __entry.type_index != 0 { // type signature check + return Err(WasmTrap::IndirectCallTypeMismatch); + } + v4 = match __entry.func_index { // static dispatch + 0 => func_0(v0, v1, table)?, // add + 1 => func_1(v0, v1, table)?, // sub + 2 => func_2(v0, v1, table)?, // mul + _ => return Err(WasmTrap::UndefinedElement), + }; + +**Why match-based dispatch?** Function pointer arrays, ``dyn Fn`` trait objects, or computed gotos all require ``unsafe``, heap allocation, or break ``no_std`` compatibility. A match statement is 100% safe, ``no_std`` compatible, and LLVM optimizes it to a jump table when arms are dense. + +The ``_ =>`` arm handles func_index values that don't match any function of the right type — a safety net for corrupted table entries. + +Structural Type Equivalence +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Wasm spec requires ``call_indirect`` to use **structural equivalence**: two type indices match if they have identical parameter and result types, regardless of index. + +.. code-block:: text + + Type 0: (i32, i32) → i32 → canonical = 0 + Type 1: (i32, i32) → i32 → canonical = 0 (same signature as type 0) + Type 2: (i32) → i32 → canonical = 2 (new signature) + +The transpiler builds a canonical type index mapping at transpile time. Both ``FuncRef.type_index`` and the type check use canonical indices. At runtime, the check is a simple integer comparison. + +Bulk Memory Operations +---------------------- + +.. spec:: Bulk Memory Operations + :id: SPEC_BULK_MEMORY + :satisfies: REQ_MEM_BULK_OPS, REQ_MEM_DATA_SEGMENTS + :tags: transpilation, memory, bulk + + memory.fill, memory.init, data.drop, memory.copy. + +*Implementation:* ``crates/herkos-runtime/src/memory.rs`` lines 149–174 + +The WebAssembly bulk memory operations allow efficient copying and initialization of memory regions without scalar load/store loops. + +``memory.fill`` +~~~~~~~~~~~~~~~ + +Fills a region of memory with a byte value. Per Wasm spec, only the low 8 bits of the value are used. + +.. code-block:: rust + + impl IsolatedMemory { + pub fn fill(&mut self, dst: usize, val: u8, len: usize) -> WasmResult<()>; + } + +Generated code: + +.. code-block:: rust + + // Wasm: memory.fill $dst $val $len + memory.fill(dst as usize, val as u8, len as usize)?; + +Traps ``OutOfBounds`` if ``[dst, dst + len)`` exceeds active memory. Length zero is a no-op. + +``memory.init`` +~~~~~~~~~~~~~~~ + +Copies data from a passive data segment into memory at runtime. Each data segment is stored as a constant ``&'static [u8]`` in the generated code. + +.. code-block:: rust + + impl IsolatedMemory { + pub fn init_data_partial(&mut self, dst: usize, data: &[u8], src_offset: usize, len: usize) -> WasmResult<()>; + } + +Generated code: + +.. code-block:: rust + + // Wasm: memory.init $data_segment $dst $src_offset $len + memory.init_data_partial(dst as usize, &DATA_SEGMENT_0, src_offset as usize, len as usize)?; + +Traps ``OutOfBounds`` if either region (source or destination) exceeds bounds: + +- Source: ``[src_offset, src_offset + len)`` must be within the data segment +- Destination: ``[dst, dst + len)`` must be within active memory + +``data.drop`` +~~~~~~~~~~~~~ + +Marks a data segment as dropped (per Wasm spec). In the safe backend this is a no-op because data segments are stored as constant references and cannot actually be deallocated. + +.. code-block:: rust + + // Wasm: data.drop $segment + // (no-op in safe backend — const slices persist) + +In future verified and hybrid backends, ``data.drop`` may enable optimizations: proving that dropped segments are never accessed again could allow proving certain addresses as never-in-bounds. diff --git a/docs/traceability/coverage.rst b/docs/traceability/coverage.rst new file mode 100644 index 0000000..290f7c3 --- /dev/null +++ b/docs/traceability/coverage.rst @@ -0,0 +1,59 @@ +Coverage Analysis +================= + +This page provides an overview of traceability coverage across the herkos project. + +Wasm 1.0 Spec Features +----------------------- + +All Wasm 1.0 specification features tracked by this project. + +.. needtable:: + :style: table + :columns: id;title;wasm_section;tags + :filter: type == 'wasm_spec' + :sort: id + +Requirements +------------ + +All herkos requirements with their outgoing links to Wasm spec features. + +.. needtable:: + :style: table + :columns: id;title;status;links + :filter: type == 'req' + :sort: id + +Specification Sections +---------------------- + +Herkos specification sections with their satisfaction links. + +.. needtable:: + :style: table + :columns: id;title;satisfies + :filter: type == 'spec' + :sort: id + +Implementation Modules +---------------------- + +Implementation modules with their requirement and spec links. + +.. needtable:: + :style: table + :columns: id;title;satisfies;implements + :filter: type == 'impl' + :sort: id + +Test Cases by File +------------------ + +Test cases with their verification links to Wasm spec features. + +.. needtable:: + :style: table + :columns: id;title;verifies + :filter: type == 'test' + :sort: id diff --git a/docs/traceability/impl.rst b/docs/traceability/impl.rst new file mode 100644 index 0000000..d3ea6d1 --- /dev/null +++ b/docs/traceability/impl.rst @@ -0,0 +1,76 @@ +Implementation Modules +====================== + +Key implementation modules in herkos-core and herkos-runtime. + +.. impl:: Wasm binary parser + :id: IMPL_PARSER + :source_file: crates/herkos-core/src/parser/mod.rs + :tags: parser, binary + :satisfies: REQ_TRANS_FUNCTIONS + :implements: WASM_BIN_MODULES, WASM_BIN_SECTIONS, WASM_BIN_TYPES, WASM_BIN_INSTRUCTIONS + + ``crates/herkos-core/src/parser/mod.rs`` + +.. impl:: Wasm-to-IR translation + :id: IMPL_IR_BUILDER + :source_file: crates/herkos-core/src/ir/builder/ + :tags: ir, builder + :satisfies: REQ_TRANS_FUNCTIONS, REQ_TRANS_CONTROL_FLOW + :implements: WASM_MOD_FUNCTIONS, WASM_EXEC_CONTROL, WASM_EXEC_CALLS + + ``crates/herkos-core/src/ir/builder/`` + +.. impl:: Safe backend (bounds-checked codegen) + :id: IMPL_BACKEND_SAFE + :source_file: crates/herkos-core/src/backend/safe.rs + :tags: backend, safe, codegen + :satisfies: REQ_MEM_BOUNDS_CHECKED, REQ_TRANS_SELF_CONTAINED + :implements: WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_MEMORY + + ``crates/herkos-core/src/backend/safe.rs`` + +.. impl:: Instruction code generation + :id: IMPL_CODEGEN_INSTR + :source_file: crates/herkos-core/src/codegen/instruction.rs + :tags: codegen, instruction + :satisfies: REQ_TRANS_FUNCTIONS + :implements: WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS, WASM_EXEC_MEMORY, WASM_EXEC_CALLS + + ``crates/herkos-core/src/codegen/instruction.rs`` + +.. impl:: Module code generation + :id: IMPL_CODEGEN_MODULE + :source_file: crates/herkos-core/src/codegen/module.rs + :tags: codegen, module + :satisfies: REQ_MOD_TWO_TYPES, REQ_TRANS_SELF_CONTAINED, REQ_TRANS_VERSION_INFO + :implements: WASM_MOD_FUNCTIONS, WASM_MOD_EXPORTS, WASM_MOD_IMPORTS, WASM_MOD_GLOBALS, WASM_MOD_TABLES + + ``crates/herkos-core/src/codegen/module.rs`` + +.. impl:: IsolatedMemory runtime + :id: IMPL_RUNTIME_MEMORY + :source_file: crates/herkos-runtime/src/memory.rs + :tags: runtime, memory + :satisfies: REQ_MEM_PAGE_MODEL, REQ_MEM_COMPILE_TIME_SIZE, REQ_MEM_BOUNDS_CHECKED, REQ_MEM_GROW_NO_ALLOC, REQ_MEM_BULK_OPS + :implements: WASM_MEMORY_TYPE, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``crates/herkos-runtime/src/memory.rs`` + +.. impl:: Table runtime (indirect calls) + :id: IMPL_RUNTIME_TABLE + :source_file: crates/herkos-runtime/src/table.rs + :tags: runtime, table + :satisfies: REQ_MOD_TABLE, REQ_TRANS_INDIRECT_CALLS + :implements: WASM_TABLE_TYPE, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_CALL_INDIRECT + + ``crates/herkos-runtime/src/table.rs`` + +.. impl:: Wasm arithmetic operations + :id: IMPL_RUNTIME_OPS + :source_file: crates/herkos-runtime/src/ops.rs + :tags: runtime, ops, arithmetic + :satisfies: REQ_ERR_TRAPS + :implements: WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``crates/herkos-runtime/src/ops.rs`` diff --git a/docs/traceability/index.rst b/docs/traceability/index.rst new file mode 100644 index 0000000..73445c6 --- /dev/null +++ b/docs/traceability/index.rst @@ -0,0 +1,14 @@ +Traceability +============ + +This section tracks coverage of the WebAssembly 1.0 specification across +herkos requirements, implementation, and tests. + +.. toctree:: + :maxdepth: 2 + + metamodel + wasm_spec/index + impl + tests + coverage diff --git a/docs/traceability/metamodel.rst b/docs/traceability/metamodel.rst new file mode 100644 index 0000000..66563c1 --- /dev/null +++ b/docs/traceability/metamodel.rst @@ -0,0 +1,280 @@ +Metamodel +========= + +This document describes the **quality metamodel** used in the herkos project — +the need types, custom fields, and link types that together form the +traceability structure. + +All configuration lives in ``ubproject.toml`` and is consumed by both +Sphinx-Needs (for documentation builds) and ubCode (for live analysis in the +editor). + +.. contents:: + :local: + :depth: 2 + +V-model overview +---------------- + +The herkos traceability follows a **V-model** structure. The left branch +decomposes the external Wasm specification into increasingly concrete +artifacts. The right branch provides verification at each level. + +**Fundamental rule: links always point upward.** Every traceability link is +authored on the *lower-level* artifact and points *up* to the higher-level +artifact it derives from. Higher-level artifacts never depend on or reference +lower-level ones. This keeps each level self-contained and independently +reviewable. + +Development branch (decomposition) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The left side of the V breaks the external specification down into +project artifacts, from abstract to concrete: + +.. mermaid:: + + flowchart TB + WASM["🔵 Wasm Spec (WASM_)
External reference baseline"] + REQ["🟢 Requirement (REQ_)
What the system must do"] + SPEC["🟡 Specification (SPEC_)
How the design realizes it"] + IMPL["🟠 Implementation (IMPL_)
Actual source code artifacts"] + + IMPL -- "satisfies" --> REQ + IMPL -- "implements" --> WASM + SPEC -- "satisfies" --> REQ + REQ -. "links" .-> WASM + + style WASM fill:#9DC3E6,stroke:#333,color:#000 + style REQ fill:#A9D18E,stroke:#333,color:#000 + style SPEC fill:#FFD966,stroke:#333,color:#000 + style IMPL fill:#F4B183,stroke:#333,color:#000 + +Each arrow represents a traceability link authored on the source node, +pointing up toward the target it derives from. + +Verification branch +^^^^^^^^^^^^^^^^^^^ + +The right side of the V provides evidence that each level behaves correctly: + +.. mermaid:: + + flowchart TB + WASM["🔵 Wasm Spec (WASM_)"] + REQ["🟢 Requirement (REQ_)"] + SPEC["🟡 Specification (SPEC_)"] + IMPL["🟠 Implementation (IMPL_)"] + TEST["🟣 Test (TEST_)
Verification evidence"] + + TEST -- "verifies" --> WASM + TEST -- "verifies" --> REQ + TEST -- "verifies" --> SPEC + TEST -- "verifies" --> IMPL + + style WASM fill:#9DC3E6,stroke:#333,color:#000 + style REQ fill:#A9D18E,stroke:#333,color:#000 + style SPEC fill:#FFD966,stroke:#333,color:#000 + style IMPL fill:#F4B183,stroke:#333,color:#000 + style TEST fill:#C5B0D5,stroke:#333,color:#000 + +Tests can verify artifacts at any level. A test always carries the +``:verifies:`` link, pointing up to the artifact it validates. + +Need types +---------- + +The project defines five need types, each representing a distinct level +in the V-model: + +.. list-table:: + :header-rows: 1 + :widths: 20 15 15 15 35 + + * - Type + - Directive + - Prefix + - Color + - Purpose + * - **Wasm Spec** + - ``.. wasm_spec::`` + - ``WASM_`` + - .. raw:: html + + #9DC3E6 + - Captures individual clauses and rules from the + `WebAssembly 1.0 specification `_. + These items are the external reference baseline — the top of the V. + They are never authored with outgoing links; they only *receive* + incoming links from lower levels. + * - **Requirement** + - ``.. req::`` + - ``REQ_`` + - .. raw:: html + + #A9D18E + - Project-level requirements derived from or motivated by the Wasm spec. + Each requirement states *what* the system must do. Requirements + reference Wasm spec items via ``:links:``. + * - **Specification** + - ``.. spec::`` + - ``SPEC_`` + - .. raw:: html + + #FFD966 + - Design-level specifications that describe *how* a requirement is + realized in the herkos architecture. Specifications link upward to + requirements via ``:satisfies:``. + * - **Implementation** + - ``.. impl::`` + - ``IMPL_`` + - .. raw:: html + + #F4B183 + - Traces to actual source code artifacts (functions, modules, structs) + that realize the design. Implementations link upward to requirements + via ``:satisfies:`` and to Wasm spec items via ``:implements:``. + * - **Test** + - ``.. test::`` + - ``TEST_`` + - .. raw:: html + + #C5B0D5 + - Test cases that provide verification evidence. Tests link upward to + the artifact they validate via ``:verifies:``. + +Custom fields +------------- + +In addition to the built-in fields (``id``, ``title``, ``status``, ``tags``), +three custom fields are defined: + +.. list-table:: + :header-rows: 1 + :widths: 20 15 65 + + * - Field + - Default + - Description + * - ``wasm_section`` + - ``""`` + - Reference to a section in the WebAssembly specification + (e.g. ``§5.4.1``). Used primarily on ``wasm_spec`` needs. + * - ``source_file`` + - ``""`` + - Path to the source file that contains the relevant code. + Used primarily on ``impl`` needs. + * - ``wasm_opcode`` + - ``""`` + - Name of the WebAssembly opcode (e.g. ``i32.add``). + Used on ``wasm_spec`` and ``req`` needs that relate to a specific + instruction. + +Link types +---------- + +Three directed link types express the traceability relationships between +needs. **All links are authored on the lower-level artifact, pointing upward** +to the higher-level artifact it derives from or validates. + +.. list-table:: + :header-rows: 1 + :widths: 18 22 22 38 + + * - Link type + - Outgoing label + - Incoming label + - Semantics + * - ``satisfies`` + - *satisfies* + - *is_satisfied_by* + - A lower-level artifact *satisfies* a higher-level one. + Used by ``SPEC_`` and ``IMPL_`` to link upward to ``REQ_`` items. + Example: ``SPEC_MEMORY_MODEL`` *satisfies* ``REQ_MEM_PAGE_MODEL``. + * - ``implements`` + - *implements* + - *is_implemented_by* + - An ``IMPL_`` artifact *implements* a ``WASM_`` spec item, showing + that a specific external specification clause is realized in code. + Example: ``IMPL_RUNTIME_MEMORY`` *implements* ``WASM_MEMORY_TYPE``. + * - ``verifies`` + - *verifies* + - *is_verified_by* + - A ``TEST_`` artifact *verifies* a higher-level artifact, providing + evidence that it behaves correctly. Can target ``WASM_``, ``REQ_``, + ``SPEC_``, or ``IMPL_`` items. + Example: ``TEST_ARITHMETIC_ADD_CORRECTNESS`` *verifies* ``WASM_I32_ADD``. + +In addition, the built-in ``:links:`` option is used by ``REQ_`` needs to +reference related ``WASM_`` spec items (a weaker association than +``satisfies``). + +Link direction principle +^^^^^^^^^^^^^^^^^^^^^^^^ + +The direction rule is essential for maintaining the independence of each +V-model level: + +- **Higher levels never reference lower levels.** A ``WASM_`` item has no + knowledge of which ``REQ_`` items exist. A ``REQ_`` item has no knowledge + of which ``SPEC_`` or ``IMPL_`` items realize it. +- **Lower levels always link upward.** The ``SPEC_``, ``IMPL_``, and + ``TEST_`` directives carry the ``:satisfies:``, ``:implements:``, and + ``:verifies:`` options respectively. +- **Sphinx-Needs computes the reverse.** When ``SPEC_X`` declares + ``:satisfies: REQ_Y``, Sphinx-Needs automatically shows ``REQ_Y`` as + *is_satisfied_by* ``SPEC_X``. No manual reverse links are needed. + +This ensures that requirements can be reviewed and baselined independently +of how — or whether — they have been implemented or tested. + +Traceability chain +------------------ + +The complete V-model traceability, showing link directions as authored +(lower → higher): + +.. list-table:: + :header-rows: 1 + :widths: 20 25 20 35 + + * - Source (lower) + - Link option + - Target (higher) + - Meaning + * - ``REQ_`` + - ``:links:`` + - ``WASM_`` + - Requirement references the Wasm spec clauses it addresses + * - ``SPEC_`` + - ``:satisfies:`` + - ``REQ_`` + - Specification satisfies a requirement + * - ``IMPL_`` + - ``:satisfies:`` + - ``REQ_`` + - Implementation satisfies a requirement + * - ``IMPL_`` + - ``:implements:`` + - ``WASM_`` + - Implementation realizes a Wasm spec clause in code + * - ``TEST_`` + - ``:verifies:`` + - ``WASM_`` / ``REQ_`` / ``SPEC_`` / ``IMPL_`` + - Test provides verification evidence for any level + +ID convention +------------- + +All need IDs must match the regex ``^[A-Z][A-Z0-9_]+`` — they start with an +uppercase letter followed by one or more uppercase letters, digits, or +underscores. Each type uses its prefix (``WASM_``, ``REQ_``, ``SPEC_``, +``IMPL_``, ``TEST_``) to make the artifact type immediately recognizable +from the ID alone. + +Coverage analysis +----------------- + +The :doc:`coverage` page uses Sphinx-Needs filters to identify gaps in +the traceability chain — requirements without tests, specifications without +implementations, and Wasm spec items without corresponding requirements. diff --git a/docs/traceability/tests.rst b/docs/traceability/tests.rst new file mode 100644 index 0000000..c8bf899 --- /dev/null +++ b/docs/traceability/tests.rst @@ -0,0 +1,2966 @@ +Test Cases +========== + +Auto-generated from ``crates/herkos-tests/tests/*.rs``. + +arithmetic +---------- + +.. test:: test_add_correctness + :id: TEST_ARITHMETIC_ADD_CORRECTNESS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_add_correctness`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_add_wrapping + :id: TEST_ARITHMETIC_ADD_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_add_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_sub_correctness + :id: TEST_ARITHMETIC_SUB_CORRECTNESS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_sub_correctness`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_sub_wrapping + :id: TEST_ARITHMETIC_SUB_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_sub_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_mul_correctness + :id: TEST_ARITHMETIC_MUL_CORRECTNESS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_mul_correctness`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_mul_wrapping + :id: TEST_ARITHMETIC_MUL_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_mul_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_const_return + :id: TEST_ARITHMETIC_CONST_RETURN + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_const_return`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_nop + :id: TEST_ARITHMETIC_NOP + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_nop`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_add_commutative + :id: TEST_ARITHMETIC_ADD_COMMUTATIVE + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_add_commutative`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_add_correctness + :id: TEST_ARITHMETIC_I64_ADD_CORRECTNESS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_add_correctness`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_add_large_values + :id: TEST_ARITHMETIC_I64_ADD_LARGE_VALUES + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_add_large_values`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_add_wrapping + :id: TEST_ARITHMETIC_I64_ADD_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_add_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_const + :id: TEST_ARITHMETIC_I64_CONST + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_const`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_fibonacci + :id: TEST_ARITHMETIC_FIBONACCI + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_fibonacci`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_gcd + :id: TEST_ARITHMETIC_GCD + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_gcd`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_gcd_commutative + :id: TEST_ARITHMETIC_GCD_COMMUTATIVE + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_gcd_commutative`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_factorial + :id: TEST_ARITHMETIC_FACTORIAL + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_factorial`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_factorial_wrapping + :id: TEST_ARITHMETIC_FACTORIAL_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_factorial_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_abs + :id: TEST_ARITHMETIC_ABS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_abs`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_abs_min_wraps + :id: TEST_ARITHMETIC_ABS_MIN_WRAPS + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_abs_min_wraps`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_add_matches_rust_wrapping + :id: TEST_ARITHMETIC_ADD_MATCHES_RUST_WRAPPING + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_add_matches_rust_wrapping`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i32_extend8_s + :id: TEST_ARITHMETIC_I32_EXTEND8_S + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i32_extend8_s`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i32_extend16_s + :id: TEST_ARITHMETIC_I32_EXTEND16_S + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i32_extend16_s`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_extend8_s + :id: TEST_ARITHMETIC_I64_EXTEND8_S + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_extend8_s`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_extend16_s + :id: TEST_ARITHMETIC_I64_EXTEND16_S + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_extend16_s`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +.. test:: test_i64_extend32_s + :id: TEST_ARITHMETIC_I64_EXTEND32_S + :source_file: crates/herkos-tests/tests/arithmetic.rs + :tags: arithmetic + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_CONST, WASM_I64_ADD, WASM_I64_CONST, WASM_NOP, WASM_CALL, WASM_EXEC_INTEGER_OPS + + ``test_i64_extend32_s`` in ``crates/herkos-tests/tests/arithmetic.rs``. + +bulk_memory +----------- + +.. test:: test_fill_writes_byte_pattern + :id: TEST_BULK_MEMORY_FILL_WRITES_BYTE_PATTERN + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_fill_writes_byte_pattern`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_fill_zero_len_is_noop + :id: TEST_BULK_MEMORY_FILL_ZERO_LEN_IS_NOOP + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_fill_zero_len_is_noop`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_fill_out_of_bounds_traps + :id: TEST_BULK_MEMORY_FILL_OUT_OF_BOUNDS_TRAPS + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_fill_out_of_bounds_traps`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_fill_byte_truncation + :id: TEST_BULK_MEMORY_FILL_BYTE_TRUNCATION + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_fill_byte_truncation`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_fill_entire_region + :id: TEST_BULK_MEMORY_FILL_ENTIRE_REGION + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_fill_entire_region`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_init_full_segment + :id: TEST_BULK_MEMORY_INIT_FULL_SEGMENT + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_init_full_segment`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_init_subrange + :id: TEST_BULK_MEMORY_INIT_SUBRANGE + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_init_subrange`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_init_zero_len_is_noop + :id: TEST_BULK_MEMORY_INIT_ZERO_LEN_IS_NOOP + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_init_zero_len_is_noop`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_init_src_out_of_bounds_traps + :id: TEST_BULK_MEMORY_INIT_SRC_OUT_OF_BOUNDS_TRAPS + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_init_src_out_of_bounds_traps`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_init_dst_out_of_bounds_traps + :id: TEST_BULK_MEMORY_INIT_DST_OUT_OF_BOUNDS_TRAPS + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_init_dst_out_of_bounds_traps`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +.. test:: test_data_drop_is_noop + :id: TEST_BULK_MEMORY_DATA_DROP_IS_NOOP + :source_file: crates/herkos-tests/tests/bulk_memory.rs + :tags: bulk_memory + :verifies: WASM_EXEC_MEMORY + + ``test_data_drop_is_noop`` in ``crates/herkos-tests/tests/bulk_memory.rs``. + +c_e2e +----- + +.. test:: test_add_i32 + :id: TEST_C_E2E_ADD_I32 + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i32`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_add_i32_wrapping + :id: TEST_C_E2E_ADD_I32_WRAPPING + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i32_wrapping`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_sub_i32 + :id: TEST_C_E2E_SUB_I32 + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_sub_i32`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_sub_i32_wrapping + :id: TEST_C_E2E_SUB_I32_WRAPPING + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_sub_i32_wrapping`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_mul_i32 + :id: TEST_C_E2E_MUL_I32 + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_mul_i32`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_mul_i32_wrapping + :id: TEST_C_E2E_MUL_I32_WRAPPING + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_mul_i32_wrapping`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_negate + :id: TEST_C_E2E_NEGATE + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_negate`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_const_42 + :id: TEST_C_E2E_CONST_42 + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_const_42`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_div_s + :id: TEST_C_E2E_DIV_S + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_div_s`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_div_s_traps_on_zero + :id: TEST_C_E2E_DIV_S_TRAPS_ON_ZERO + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_div_s_traps_on_zero`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_rem_s + :id: TEST_C_E2E_REM_S + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_rem_s`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_rem_s_traps_on_zero + :id: TEST_C_E2E_REM_S_TRAPS_ON_ZERO + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_rem_s_traps_on_zero`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_bitwise_and + :id: TEST_C_E2E_BITWISE_AND + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_and`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_bitwise_or + :id: TEST_C_E2E_BITWISE_OR + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_or`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_bitwise_xor + :id: TEST_C_E2E_BITWISE_XOR + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_xor`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_shift_left + :id: TEST_C_E2E_SHIFT_LEFT + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_shift_left`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_shift_right_unsigned + :id: TEST_C_E2E_SHIFT_RIGHT_UNSIGNED + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_shift_right_unsigned`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_add_i64 + :id: TEST_C_E2E_ADD_I64 + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i64`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_add_i64_large + :id: TEST_C_E2E_ADD_I64_LARGE + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i64_large`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_factorial + :id: TEST_C_E2E_FACTORIAL + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_factorial`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_sum_1_to_n + :id: TEST_C_E2E_SUM_1_TO_N + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_sum_1_to_n`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_gcd + :id: TEST_C_E2E_GCD + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_gcd`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_diff_of_squares + :id: TEST_C_E2E_DIFF_OF_SQUARES + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_diff_of_squares`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_matches_native_c_semantics + :id: TEST_C_E2E_MATCHES_NATIVE_C_SEMANTICS + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_matches_native_c_semantics`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_commutative_ops + :id: TEST_C_E2E_COMMUTATIVE_OPS + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_commutative_ops`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +.. test:: test_division_edge_cases + :id: TEST_C_E2E_DIVISION_EDGE_CASES + :source_file: crates/herkos-tests/tests/c_e2e.rs + :tags: c_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_DIV_S, WASM_I32_REM_S, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_division_edge_cases`` in ``crates/herkos-tests/tests/c_e2e.rs``. + +c_e2e_i64 +--------- + +.. test:: test_mul_i64 + :id: TEST_C_E2E_I64_MUL_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_mul_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_sub_i64 + :id: TEST_C_E2E_I64_SUB_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_sub_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_div_i64_s + :id: TEST_C_E2E_I64_DIV_I64_S + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_div_i64_s`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_div_i64_traps_on_zero + :id: TEST_C_E2E_I64_DIV_I64_TRAPS_ON_ZERO + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_div_i64_traps_on_zero`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_rem_i64_s + :id: TEST_C_E2E_I64_REM_I64_S + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_rem_i64_s`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_bitwise_i64 + :id: TEST_C_E2E_I64_BITWISE_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_bitwise_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_shift_i64 + :id: TEST_C_E2E_I64_SHIFT_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_shift_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_negate_i64 + :id: TEST_C_E2E_I64_NEGATE_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_negate_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_fib_i64 + :id: TEST_C_E2E_I64_FIB_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_fib_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_factorial_i64 + :id: TEST_C_E2E_I64_FACTORIAL_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_factorial_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +.. test:: test_division_invariant_i64 + :id: TEST_C_E2E_I64_DIVISION_INVARIANT_I64 + :source_file: crates/herkos-tests/tests/c_e2e_i64.rs + :tags: c_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_DIV_S, WASM_I64_REM_S, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_division_invariant_i64`` in ``crates/herkos-tests/tests/c_e2e_i64.rs``. + +c_e2e_loops +----------- + +.. test:: test_power + :id: TEST_C_E2E_LOOPS_POWER + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_power`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_collatz_steps + :id: TEST_C_E2E_LOOPS_COLLATZ_STEPS + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_collatz_steps`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_is_prime + :id: TEST_C_E2E_LOOPS_IS_PRIME + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_is_prime`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_count_primes + :id: TEST_C_E2E_LOOPS_COUNT_PRIMES + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_count_primes`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_sum_of_divisors + :id: TEST_C_E2E_LOOPS_SUM_OF_DIVISORS + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_sum_of_divisors`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_is_perfect + :id: TEST_C_E2E_LOOPS_IS_PERFECT + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_is_perfect`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +.. test:: test_digital_root + :id: TEST_C_E2E_LOOPS_DIGITAL_ROOT + :source_file: crates/herkos-tests/tests/c_e2e_loops.rs + :tags: c_e2e_loops + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_digital_root`` in ``crates/herkos-tests/tests/c_e2e_loops.rs``. + +c_e2e_memory +------------ + +.. test:: test_store_and_load + :id: TEST_C_E2E_MEMORY_STORE_AND_LOAD + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_store_and_load`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_array_sum + :id: TEST_C_E2E_MEMORY_ARRAY_SUM + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_array_sum`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_array_max + :id: TEST_C_E2E_MEMORY_ARRAY_MAX + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_array_max`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_array_max_negative + :id: TEST_C_E2E_MEMORY_ARRAY_MAX_NEGATIVE + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_array_max_negative`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_dot_product + :id: TEST_C_E2E_MEMORY_DOT_PRODUCT + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_dot_product`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_array_reverse + :id: TEST_C_E2E_MEMORY_ARRAY_REVERSE + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_array_reverse`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_array_reverse_even + :id: TEST_C_E2E_MEMORY_ARRAY_REVERSE_EVEN + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_array_reverse_even`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_bubble_sort + :id: TEST_C_E2E_MEMORY_BUBBLE_SORT + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_bubble_sort`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +.. test:: test_bubble_sort_already_sorted + :id: TEST_C_E2E_MEMORY_BUBBLE_SORT_ALREADY_SORTED + :source_file: crates/herkos-tests/tests/c_e2e_memory.rs + :tags: c_e2e_memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_bubble_sort_already_sorted`` in ``crates/herkos-tests/tests/c_e2e_memory.rs``. + +call_import_transitive +---------------------- + +.. test:: test_direct_call_transitive_import + :id: TEST_CALL_IMPORT_TRANSITIVE_DIRECT_CALL_TRANSITIVE_IMPORT + :source_file: crates/herkos-tests/tests/call_import_transitive.rs + :tags: call_import_transitive + :verifies: WASM_CALL, WASM_MOD_IMPORTS + + ``test_direct_call_transitive_import`` in ``crates/herkos-tests/tests/call_import_transitive.rs``. + +.. test:: test_caller_multiple_invocations + :id: TEST_CALL_IMPORT_TRANSITIVE_CALLER_MULTIPLE_INVOCATIONS + :source_file: crates/herkos-tests/tests/call_import_transitive.rs + :tags: call_import_transitive + :verifies: WASM_CALL, WASM_MOD_IMPORTS + + ``test_caller_multiple_invocations`` in ``crates/herkos-tests/tests/call_import_transitive.rs``. + +control_flow +------------ + +.. test:: test_simple_if_true + :id: TEST_CONTROL_FLOW_SIMPLE_IF_TRUE + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_simple_if_true`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_simple_if_false + :id: TEST_CONTROL_FLOW_SIMPLE_IF_FALSE + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_simple_if_false`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_max_first_larger + :id: TEST_CONTROL_FLOW_MAX_FIRST_LARGER + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_max_first_larger`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_max_second_larger + :id: TEST_CONTROL_FLOW_MAX_SECOND_LARGER + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_max_second_larger`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_max_equal + :id: TEST_CONTROL_FLOW_MAX_EQUAL + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_max_equal`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_countdown_loop + :id: TEST_CONTROL_FLOW_COUNTDOWN_LOOP + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_countdown_loop`` in ``crates/herkos-tests/tests/control_flow.rs``. + +.. test:: test_countdown_loop_zero + :id: TEST_CONTROL_FLOW_COUNTDOWN_LOOP_ZERO + :source_file: crates/herkos-tests/tests/control_flow.rs + :tags: control_flow + :verifies: WASM_IF, WASM_BLOCK, WASM_LOOP, WASM_BR_IF, WASM_EXEC_CONTROL + + ``test_countdown_loop_zero`` in ``crates/herkos-tests/tests/control_flow.rs``. + +early_return +------------ + +.. test:: test_early_return_negative + :id: TEST_EARLY_RETURN_EARLY_RETURN_NEGATIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_early_return_negative`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_early_return_positive + :id: TEST_EARLY_RETURN_EARLY_RETURN_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_early_return_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_first_positive_already_positive + :id: TEST_EARLY_RETURN_FIRST_POSITIVE_ALREADY_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_first_positive_already_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_first_positive_from_zero + :id: TEST_EARLY_RETURN_FIRST_POSITIVE_FROM_ZERO + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_first_positive_from_zero`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_first_positive_from_negative + :id: TEST_EARLY_RETURN_FIRST_POSITIVE_FROM_NEGATIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_first_positive_from_negative`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_sum_early_exit_invalid + :id: TEST_EARLY_RETURN_SUM_EARLY_EXIT_INVALID + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_sum_early_exit_invalid`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_sum_normal + :id: TEST_EARLY_RETURN_SUM_NORMAL + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_sum_normal`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_nested_return_first_positive + :id: TEST_EARLY_RETURN_NESTED_RETURN_FIRST_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_nested_return_first_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_nested_return_second_positive + :id: TEST_EARLY_RETURN_NESTED_RETURN_SECOND_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_nested_return_second_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_nested_return_both_positive + :id: TEST_EARLY_RETURN_NESTED_RETURN_BOTH_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_nested_return_both_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +.. test:: test_nested_return_neither_positive + :id: TEST_EARLY_RETURN_NESTED_RETURN_NEITHER_POSITIVE + :source_file: crates/herkos-tests/tests/early_return.rs + :tags: early_return + :verifies: WASM_RETURN, WASM_IF, WASM_EXEC_CONTROL + + ``test_nested_return_neither_positive`` in ``crates/herkos-tests/tests/early_return.rs``. + +function_calls +-------------- + +.. test:: test_call_helper_basic + :id: TEST_FUNCTION_CALLS_CALL_HELPER_BASIC + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_helper_basic`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_helper_wrapping + :id: TEST_FUNCTION_CALLS_CALL_HELPER_WRAPPING + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_helper_wrapping`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_helper_direct_vs_indirect + :id: TEST_FUNCTION_CALLS_CALL_HELPER_DIRECT_VS_INDIRECT + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_helper_direct_vs_indirect`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_recursive_fib + :id: TEST_FUNCTION_CALLS_RECURSIVE_FIB + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_recursive_fib`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_recursive_fib_matches_iterative + :id: TEST_FUNCTION_CALLS_RECURSIVE_FIB_MATCHES_ITERATIVE + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_recursive_fib_matches_iterative`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_with_memory_store_via_call + :id: TEST_FUNCTION_CALLS_CALL_WITH_MEMORY_STORE_VIA_CALL + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_with_memory_store_via_call`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_with_memory_multiple_stores + :id: TEST_FUNCTION_CALLS_CALL_WITH_MEMORY_MULTIPLE_STORES + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_with_memory_multiple_stores`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_i64_basic + :id: TEST_FUNCTION_CALLS_CALL_I64_BASIC + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_i64_basic`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_i64_large_values + :id: TEST_FUNCTION_CALLS_CALL_I64_LARGE_VALUES + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_i64_large_values`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_i64_wrapping + :id: TEST_FUNCTION_CALLS_CALL_I64_WRAPPING + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_i64_wrapping`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_with_globals_set_and_get + :id: TEST_FUNCTION_CALLS_CALL_WITH_GLOBALS_SET_AND_GET + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_with_globals_set_and_get`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_with_globals_multiple + :id: TEST_FUNCTION_CALLS_CALL_WITH_GLOBALS_MULTIPLE + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_with_globals_multiple`` in ``crates/herkos-tests/tests/function_calls.rs``. + +.. test:: test_call_with_globals_isolation + :id: TEST_FUNCTION_CALLS_CALL_WITH_GLOBALS_ISOLATION + :source_file: crates/herkos-tests/tests/function_calls.rs + :tags: function_calls + :verifies: WASM_CALL, WASM_CALL_INDIRECT, WASM_GLOBAL_GET, WASM_GLOBAL_SET, WASM_I32_LOAD, WASM_I32_STORE, WASM_I64_ADD, WASM_EXEC_CALLS + + ``test_call_with_globals_isolation`` in ``crates/herkos-tests/tests/function_calls.rs``. + +import_memory +------------- + +.. test:: test_library_module_memory_lending + :id: TEST_IMPORT_MEMORY_LIBRARY_MODULE_MEMORY_LENDING + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_library_module_memory_lending`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_library_module_write_to_borrowed_memory + :id: TEST_IMPORT_MEMORY_LIBRARY_MODULE_WRITE_TO_BORROWED_MEMORY + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_library_module_write_to_borrowed_memory`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_library_module_roundtrip + :id: TEST_IMPORT_MEMORY_LIBRARY_MODULE_ROUNDTRIP + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_library_module_roundtrip`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_library_module_multiple_offsets + :id: TEST_IMPORT_MEMORY_LIBRARY_MODULE_MULTIPLE_OFFSETS + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_library_module_multiple_offsets`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_library_module_imports_and_memory + :id: TEST_IMPORT_MEMORY_LIBRARY_MODULE_IMPORTS_AND_MEMORY + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_library_module_imports_and_memory`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_memory_size_with_import + :id: TEST_IMPORT_MEMORY_MEMORY_SIZE_WITH_IMPORT + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_memory_size_with_import`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_memory_grow_borrowed + :id: TEST_IMPORT_MEMORY_MEMORY_GROW_BORROWED + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_memory_grow_borrowed`` in ``crates/herkos-tests/tests/import_memory.rs``. + +.. test:: test_memory_isolation_different_modules + :id: TEST_IMPORT_MEMORY_MEMORY_ISOLATION_DIFFERENT_MODULES + :source_file: crates/herkos-tests/tests/import_memory.rs + :tags: import_memory + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_I32_LOAD, WASM_I32_STORE + + ``test_memory_isolation_different_modules`` in ``crates/herkos-tests/tests/import_memory.rs``. + +import_multi +------------ + +.. test:: test_mixed_local_and_import_calls + :id: TEST_IMPORT_MULTI_MIXED_LOCAL_AND_IMPORT_CALLS + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_mixed_local_and_import_calls`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_multiple_imports_called + :id: TEST_IMPORT_MULTI_MULTIPLE_IMPORTS_CALLED + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_multiple_imports_called`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_wasi_import + :id: TEST_IMPORT_MULTI_WASI_IMPORT + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_wasi_import`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_call_all_imports + :id: TEST_IMPORT_MULTI_CALL_ALL_IMPORTS + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_call_all_imports`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_call_local_functions_only + :id: TEST_IMPORT_MULTI_CALL_LOCAL_FUNCTIONS_ONLY + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_call_local_functions_only`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_local_then_import_sequence + :id: TEST_IMPORT_MULTI_LOCAL_THEN_IMPORT_SEQUENCE + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_local_then_import_sequence`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_counter_management + :id: TEST_IMPORT_MULTI_COUNTER_MANAGEMENT + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_counter_management`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_mixed_import_sources + :id: TEST_IMPORT_MULTI_MIXED_IMPORT_SOURCES + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_mixed_import_sources`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_call_sequence_complexity + :id: TEST_IMPORT_MULTI_CALL_SEQUENCE_COMPLEXITY + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_call_sequence_complexity`` in ``crates/herkos-tests/tests/import_multi.rs``. + +.. test:: test_multiple_hosts_with_different_implementations + :id: TEST_IMPORT_MULTI_MULTIPLE_HOSTS_WITH_DIFFERENT_IMPLEMENTATIONS + :source_file: crates/herkos-tests/tests/import_multi.rs + :tags: import_multi + :verifies: WASM_MOD_IMPORTS, WASM_CALL, WASM_EXEC_CALLS + + ``test_multiple_hosts_with_different_implementations`` in ``crates/herkos-tests/tests/import_multi.rs``. + +import_traits +------------- + +.. test:: test_trait_generation + :id: TEST_IMPORT_TRAITS_TRAIT_GENERATION + :source_file: crates/herkos-tests/tests/import_traits.rs + :tags: import_traits + :verifies: WASM_MOD_IMPORTS, WASM_MOD_EXPORTS, WASM_EXTERNAL_TYPE + + ``test_trait_generation`` in ``crates/herkos-tests/tests/import_traits.rs``. + +.. test:: test_wasi_import + :id: TEST_IMPORT_TRAITS_WASI_IMPORT + :source_file: crates/herkos-tests/tests/import_traits.rs + :tags: import_traits + :verifies: WASM_MOD_IMPORTS, WASM_MOD_EXPORTS, WASM_EXTERNAL_TYPE + + ``test_wasi_import`` in ``crates/herkos-tests/tests/import_traits.rs``. + +.. test:: test_multiple_trait_bounds + :id: TEST_IMPORT_TRAITS_MULTIPLE_TRAIT_BOUNDS + :source_file: crates/herkos-tests/tests/import_traits.rs + :tags: import_traits + :verifies: WASM_MOD_IMPORTS, WASM_MOD_EXPORTS, WASM_EXTERNAL_TYPE + + ``test_multiple_trait_bounds`` in ``crates/herkos-tests/tests/import_traits.rs``. + +indirect_call_import +-------------------- + +.. test:: test_call_indirect_with_import + :id: TEST_INDIRECT_CALL_IMPORT_CALL_INDIRECT_WITH_IMPORT + :source_file: crates/herkos-tests/tests/indirect_call_import.rs + :tags: indirect_call_import + :verifies: WASM_CALL_INDIRECT, WASM_MOD_IMPORTS, WASM_MOD_TABLES, WASM_MOD_ELEM + + ``test_call_indirect_with_import`` in ``crates/herkos-tests/tests/indirect_call_import.rs``. + +.. test:: test_call_indirect_multiple_dispatches + :id: TEST_INDIRECT_CALL_IMPORT_CALL_INDIRECT_MULTIPLE_DISPATCHES + :source_file: crates/herkos-tests/tests/indirect_call_import.rs + :tags: indirect_call_import + :verifies: WASM_CALL_INDIRECT, WASM_MOD_IMPORTS, WASM_MOD_TABLES, WASM_MOD_ELEM + + ``test_call_indirect_multiple_dispatches`` in ``crates/herkos-tests/tests/indirect_call_import.rs``. + +indirect_calls +-------------- + +.. test:: test_binop_dispatch_add + :id: TEST_INDIRECT_CALLS_BINOP_DISPATCH_ADD + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_dispatch_add`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_binop_dispatch_sub + :id: TEST_INDIRECT_CALLS_BINOP_DISPATCH_SUB + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_dispatch_sub`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_binop_dispatch_mul + :id: TEST_INDIRECT_CALLS_BINOP_DISPATCH_MUL + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_dispatch_mul`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_binop_dispatch_all_ops + :id: TEST_INDIRECT_CALLS_BINOP_DISPATCH_ALL_OPS + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_dispatch_all_ops`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_binop_direct_vs_indirect + :id: TEST_INDIRECT_CALLS_BINOP_DIRECT_VS_INDIRECT + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_direct_vs_indirect`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_unop_dispatch_negate + :id: TEST_INDIRECT_CALLS_UNOP_DISPATCH_NEGATE + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_unop_dispatch_negate`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_unop_direct_vs_indirect + :id: TEST_INDIRECT_CALLS_UNOP_DIRECT_VS_INDIRECT + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_unop_direct_vs_indirect`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_binop_dispatch_hits_unop_entry + :id: TEST_INDIRECT_CALLS_BINOP_DISPATCH_HITS_UNOP_ENTRY + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_binop_dispatch_hits_unop_entry`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_unop_dispatch_hits_binop_entry + :id: TEST_INDIRECT_CALLS_UNOP_DISPATCH_HITS_BINOP_ENTRY + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_unop_dispatch_hits_binop_entry`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_undefined_element + :id: TEST_INDIRECT_CALLS_UNDEFINED_ELEMENT + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_undefined_element`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_table_out_of_bounds + :id: TEST_INDIRECT_CALLS_TABLE_OUT_OF_BOUNDS + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_table_out_of_bounds`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +.. test:: test_negative_index_out_of_bounds + :id: TEST_INDIRECT_CALLS_NEGATIVE_INDEX_OUT_OF_BOUNDS + :source_file: crates/herkos-tests/tests/indirect_calls.rs + :tags: indirect_calls + :verifies: WASM_CALL_INDIRECT, WASM_MOD_TABLES, WASM_MOD_ELEM, WASM_EXEC_CALLS + + ``test_negative_index_out_of_bounds`` in ``crates/herkos-tests/tests/indirect_calls.rs``. + +inter_module_lending +-------------------- + +.. test:: test_host_writes_library_reads + :id: TEST_INTER_MODULE_LENDING_HOST_WRITES_LIBRARY_READS + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_host_writes_library_reads`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_library_writes_host_reads + :id: TEST_INTER_MODULE_LENDING_LIBRARY_WRITES_HOST_READS + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_library_writes_host_reads`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_roundtrip_through_library + :id: TEST_INTER_MODULE_LENDING_ROUNDTRIP_THROUGH_LIBRARY + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_roundtrip_through_library`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_library_with_imports_and_memory + :id: TEST_INTER_MODULE_LENDING_LIBRARY_WITH_IMPORTS_AND_MEMORY + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_library_with_imports_and_memory`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_two_libraries_same_memory + :id: TEST_INTER_MODULE_LENDING_TWO_LIBRARIES_SAME_MEMORY + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_two_libraries_same_memory`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_multiple_module_types_shared_host + :id: TEST_INTER_MODULE_LENDING_MULTIPLE_MODULE_TYPES_SHARED_HOST + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_multiple_module_types_shared_host`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +.. test:: test_memory_grow_visible_across_modules + :id: TEST_INTER_MODULE_LENDING_MEMORY_GROW_VISIBLE_ACROSS_MODULES + :source_file: crates/herkos-tests/tests/inter_module_lending.rs + :tags: inter_module_lending + :verifies: WASM_MOD_IMPORTS, WASM_MOD_MEMORIES, WASM_MEMORY_GROW + + ``test_memory_grow_visible_across_modules`` in ``crates/herkos-tests/tests/inter_module_lending.rs``. + +locals +------ + +.. test:: test_func_0_basic + :id: TEST_LOCALS_FUNC_0_BASIC + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_0_basic`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_0_zeros + :id: TEST_LOCALS_FUNC_0_ZEROS + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_0_zeros`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_0_negative + :id: TEST_LOCALS_FUNC_0_NEGATIVE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_0_negative`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_0_large_values + :id: TEST_LOCALS_FUNC_0_LARGE_VALUES + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_0_large_values`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_1_i32_local + :id: TEST_LOCALS_FUNC_1_I32_LOCAL + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_1_i32_local`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_1_zero + :id: TEST_LOCALS_FUNC_1_ZERO + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_1_zero`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_1_negative + :id: TEST_LOCALS_FUNC_1_NEGATIVE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_1_negative`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_2_tee_basic + :id: TEST_LOCALS_FUNC_2_TEE_BASIC + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_2_tee_basic`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_2_tee_zero + :id: TEST_LOCALS_FUNC_2_TEE_ZERO + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_2_tee_zero`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_2_tee_negative + :id: TEST_LOCALS_FUNC_2_TEE_NEGATIVE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_2_tee_negative`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_2_tee_large + :id: TEST_LOCALS_FUNC_2_TEE_LARGE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_2_tee_large`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_3_zero_initialization + :id: TEST_LOCALS_FUNC_3_ZERO_INITIALIZATION + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_3_zero_initialization`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_3_zero_init_negative + :id: TEST_LOCALS_FUNC_3_ZERO_INIT_NEGATIVE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_3_zero_init_negative`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_3_zero_init_zero + :id: TEST_LOCALS_FUNC_3_ZERO_INIT_ZERO + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_3_zero_init_zero`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_4_running_sum_basic + :id: TEST_LOCALS_FUNC_4_RUNNING_SUM_BASIC + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_4_running_sum_basic`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_4_running_sum_zeros + :id: TEST_LOCALS_FUNC_4_RUNNING_SUM_ZEROS + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_4_running_sum_zeros`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_4_running_sum_mixed + :id: TEST_LOCALS_FUNC_4_RUNNING_SUM_MIXED + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_4_running_sum_mixed`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_4_running_sum_negative + :id: TEST_LOCALS_FUNC_4_RUNNING_SUM_NEGATIVE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_4_running_sum_negative`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_func_4_running_sum_large + :id: TEST_LOCALS_FUNC_4_RUNNING_SUM_LARGE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_func_4_running_sum_large`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_local_bounds + :id: TEST_LOCALS_LOCAL_BOUNDS + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_local_bounds`` in ``crates/herkos-tests/tests/locals.rs``. + +.. test:: test_all_locals_functions_accessible + :id: TEST_LOCALS_ALL_LOCALS_FUNCTIONS_ACCESSIBLE + :source_file: crates/herkos-tests/tests/locals.rs + :tags: locals + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE, WASM_EXEC_VARIABLE + + ``test_all_locals_functions_accessible`` in ``crates/herkos-tests/tests/locals.rs``. + +locals_aliasing +--------------- + +.. test:: test_mod10_tee_n10_regression + :id: TEST_LOCALS_ALIASING_MOD10_TEE_N10_REGRESSION + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_mod10_tee_n10_regression`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_mod10_tee_exact_zero_remainders + :id: TEST_LOCALS_ALIASING_MOD10_TEE_EXACT_ZERO_REMAINDERS + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_mod10_tee_exact_zero_remainders`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_mod10_tee_nonzero_remainders + :id: TEST_LOCALS_ALIASING_MOD10_TEE_NONZERO_REMAINDERS + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_mod10_tee_nonzero_remainders`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_preserve_across_set_basic + :id: TEST_LOCALS_ALIASING_PRESERVE_ACROSS_SET_BASIC + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_preserve_across_set_basic`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_preserve_across_set_one + :id: TEST_LOCALS_ALIASING_PRESERVE_ACROSS_SET_ONE + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_preserve_across_set_one`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_preserve_across_set_zero + :id: TEST_LOCALS_ALIASING_PRESERVE_ACROSS_SET_ZERO + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_preserve_across_set_zero`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_preserve_across_set_negative + :id: TEST_LOCALS_ALIASING_PRESERVE_ACROSS_SET_NEGATIVE + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_preserve_across_set_negative`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_preserve_across_set_varied + :id: TEST_LOCALS_ALIASING_PRESERVE_ACROSS_SET_VARIED + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_preserve_across_set_varied`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_snap_vs_tee_basic + :id: TEST_LOCALS_ALIASING_GET_SNAP_VS_TEE_BASIC + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_snap_vs_tee_basic`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_snap_vs_tee_zero_b + :id: TEST_LOCALS_ALIASING_GET_SNAP_VS_TEE_ZERO_B + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_snap_vs_tee_zero_b`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_snap_vs_tee_zero_a + :id: TEST_LOCALS_ALIASING_GET_SNAP_VS_TEE_ZERO_A + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_snap_vs_tee_zero_a`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_snap_vs_tee_negative_b + :id: TEST_LOCALS_ALIASING_GET_SNAP_VS_TEE_NEGATIVE_B + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_snap_vs_tee_negative_b`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_snap_vs_tee_equal + :id: TEST_LOCALS_ALIASING_GET_SNAP_VS_TEE_EQUAL + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_snap_vs_tee_equal`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_tee_then_set_basic + :id: TEST_LOCALS_ALIASING_GET_TEE_THEN_SET_BASIC + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_tee_then_set_basic`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_tee_then_set_zero_b + :id: TEST_LOCALS_ALIASING_GET_TEE_THEN_SET_ZERO_B + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_tee_then_set_zero_b`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_tee_then_set_zero_a + :id: TEST_LOCALS_ALIASING_GET_TEE_THEN_SET_ZERO_A + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_tee_then_set_zero_a`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_tee_then_set_negative + :id: TEST_LOCALS_ALIASING_GET_TEE_THEN_SET_NEGATIVE + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_tee_then_set_negative`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +.. test:: test_get_tee_then_set_varied + :id: TEST_LOCALS_ALIASING_GET_TEE_THEN_SET_VARIED + :source_file: crates/herkos-tests/tests/locals_aliasing.rs + :tags: locals_aliasing + :verifies: WASM_LOCAL_GET, WASM_LOCAL_SET, WASM_LOCAL_TEE + + ``test_get_tee_then_set_varied`` in ``crates/herkos-tests/tests/locals_aliasing.rs``. + +memory +------ + +.. test:: test_memory_store + :id: TEST_MEMORY_MEMORY_STORE + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_store`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_load + :id: TEST_MEMORY_MEMORY_LOAD + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_load`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_roundtrip + :id: TEST_MEMORY_MEMORY_ROUNDTRIP + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_roundtrip`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_roundtrip_different_values + :id: TEST_MEMORY_MEMORY_ROUNDTRIP_DIFFERENT_VALUES + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_roundtrip_different_values`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_out_of_bounds + :id: TEST_MEMORY_OUT_OF_BOUNDS + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_out_of_bounds`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_store_at_boundary + :id: TEST_MEMORY_MEMORY_STORE_AT_BOUNDARY + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_store_at_boundary`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_sum_basic + :id: TEST_MEMORY_MEMORY_SUM_BASIC + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_sum_basic`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_sum_empty + :id: TEST_MEMORY_MEMORY_SUM_EMPTY + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_sum_empty`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_sum_single + :id: TEST_MEMORY_MEMORY_SUM_SINGLE + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_sum_single`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_sum_negative_values + :id: TEST_MEMORY_MEMORY_SUM_NEGATIVE_VALUES + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_sum_negative_values`` in ``crates/herkos-tests/tests/memory.rs``. + +.. test:: test_memory_sum_as_static + :id: TEST_MEMORY_MEMORY_SUM_AS_STATIC + :source_file: crates/herkos-tests/tests/memory.rs + :tags: memory + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_memory_sum_as_static`` in ``crates/herkos-tests/tests/memory.rs``. + +memory_grow +----------- + +.. test:: test_initial_size + :id: TEST_MEMORY_GROW_INITIAL_SIZE + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_initial_size`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +.. test:: test_grow_success + :id: TEST_MEMORY_GROW_GROW_SUCCESS + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_grow_success`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +.. test:: test_grow_multiple + :id: TEST_MEMORY_GROW_GROW_MULTIPLE + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_grow_multiple`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +.. test:: test_grow_failure_returns_neg1 + :id: TEST_MEMORY_GROW_GROW_FAILURE_RETURNS_NEG1 + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_grow_failure_returns_neg1`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +.. test:: test_grow_then_use_new_memory + :id: TEST_MEMORY_GROW_GROW_THEN_USE_NEW_MEMORY + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_grow_then_use_new_memory`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +.. test:: test_grow_zero + :id: TEST_MEMORY_GROW_GROW_ZERO + :source_file: crates/herkos-tests/tests/memory_grow.rs + :tags: memory_grow + :verifies: WASM_MEMORY_SIZE, WASM_MEMORY_GROW, WASM_EXEC_MEMORY + + ``test_grow_zero`` in ``crates/herkos-tests/tests/memory_grow.rs``. + +module_wrapper +-------------- + +.. test:: test_counter_initial_value + :id: TEST_MODULE_WRAPPER_COUNTER_INITIAL_VALUE + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_counter_initial_value`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_counter_increment + :id: TEST_MODULE_WRAPPER_COUNTER_INCREMENT + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_counter_increment`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_counter_get_count_after_increment + :id: TEST_MODULE_WRAPPER_COUNTER_GET_COUNT_AFTER_INCREMENT + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_counter_get_count_after_increment`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_counter_instances_are_isolated + :id: TEST_MODULE_WRAPPER_COUNTER_INSTANCES_ARE_ISOLATED + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_counter_instances_are_isolated`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_hello_data_init + :id: TEST_MODULE_WRAPPER_HELLO_DATA_INIT + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_hello_data_init`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_hello_data_second_byte + :id: TEST_MODULE_WRAPPER_HELLO_DATA_SECOND_BYTE + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_hello_data_second_byte`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_data_segments_active_init + :id: TEST_MODULE_WRAPPER_DATA_SEGMENTS_ACTIVE_INIT + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_data_segments_active_init`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_data_segments_second_active_init + :id: TEST_MODULE_WRAPPER_DATA_SEGMENTS_SECOND_ACTIVE_INIT + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_data_segments_second_active_init`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_data_segments_byte_access + :id: TEST_MODULE_WRAPPER_DATA_SEGMENTS_BYTE_ACCESS + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_data_segments_byte_access`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_data_segments_passive_does_not_crash + :id: TEST_MODULE_WRAPPER_DATA_SEGMENTS_PASSIVE_DOES_NOT_CRASH + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_data_segments_passive_does_not_crash`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_const_global + :id: TEST_MODULE_WRAPPER_CONST_GLOBAL + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_const_global`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +.. test:: test_const_global_value + :id: TEST_MODULE_WRAPPER_CONST_GLOBAL_VALUE + :source_file: crates/herkos-tests/tests/module_wrapper.rs + :tags: module_wrapper + :verifies: WASM_MOD_GLOBALS, WASM_MOD_DATA, WASM_GLOBAL_GET, WASM_EXEC_INSTANTIATION + + ``test_const_global_value`` in ``crates/herkos-tests/tests/module_wrapper.rs``. + +numeric_ops +----------- + +.. test:: test_i64_div_s + :id: TEST_NUMERIC_OPS_I64_DIV_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_div_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_div_s_trap_zero + :id: TEST_NUMERIC_OPS_I64_DIV_S_TRAP_ZERO + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_div_s_trap_zero`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_bitand + :id: TEST_NUMERIC_OPS_I64_BITAND + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_bitand`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_shl + :id: TEST_NUMERIC_OPS_I64_SHL + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_shl`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_lt_s + :id: TEST_NUMERIC_OPS_I64_LT_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_lt_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_clz + :id: TEST_NUMERIC_OPS_I64_CLZ + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_clz`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_rotl + :id: TEST_NUMERIC_OPS_I64_ROTL + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_rotl`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_rem_u + :id: TEST_NUMERIC_OPS_I64_REM_U + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_rem_u`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_rem_u_trap_zero + :id: TEST_NUMERIC_OPS_I64_REM_U_TRAP_ZERO + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_rem_u_trap_zero`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_div + :id: TEST_NUMERIC_OPS_F64_DIV + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_div`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_min + :id: TEST_NUMERIC_OPS_F64_MIN + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_min`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_lt + :id: TEST_NUMERIC_OPS_F64_LT + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_lt`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_sqrt + :id: TEST_NUMERIC_OPS_F64_SQRT + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_sqrt`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_floor + :id: TEST_NUMERIC_OPS_F64_FLOOR + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_floor`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_ceil + :id: TEST_NUMERIC_OPS_F64_CEIL + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_ceil`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_neg + :id: TEST_NUMERIC_OPS_F64_NEG + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_neg`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_wrap_i64 + :id: TEST_NUMERIC_OPS_I32_WRAP_I64 + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_wrap_i64`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_extend_i32_s + :id: TEST_NUMERIC_OPS_I64_EXTEND_I32_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_extend_i32_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_extend_i32_u + :id: TEST_NUMERIC_OPS_I64_EXTEND_I32_U + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_extend_i32_u`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_extend8_s + :id: TEST_NUMERIC_OPS_I32_EXTEND8_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_extend8_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_extend16_s + :id: TEST_NUMERIC_OPS_I32_EXTEND16_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_extend16_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_extend8_s + :id: TEST_NUMERIC_OPS_I64_EXTEND8_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_extend8_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_extend16_s + :id: TEST_NUMERIC_OPS_I64_EXTEND16_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_extend16_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i64_extend32_s + :id: TEST_NUMERIC_OPS_I64_EXTEND32_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i64_extend32_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_convert_i32_s + :id: TEST_NUMERIC_OPS_F64_CONVERT_I32_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_convert_i32_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_trunc_f64_s + :id: TEST_NUMERIC_OPS_I32_TRUNC_F64_S + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_trunc_f64_s`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_trunc_f64_s_trap_nan + :id: TEST_NUMERIC_OPS_I32_TRUNC_F64_S_TRAP_NAN + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_trunc_f64_s_trap_nan`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_trunc_f64_s_trap_overflow + :id: TEST_NUMERIC_OPS_I32_TRUNC_F64_S_TRAP_OVERFLOW + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_trunc_f64_s_trap_overflow`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f32_demote_f64 + :id: TEST_NUMERIC_OPS_F32_DEMOTE_F64 + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f32_demote_f64`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f64_promote_f32 + :id: TEST_NUMERIC_OPS_F64_PROMOTE_F32 + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f64_promote_f32`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_i32_reinterpret_f32 + :id: TEST_NUMERIC_OPS_I32_REINTERPRET_F32 + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_i32_reinterpret_f32`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +.. test:: test_f32_reinterpret_i32 + :id: TEST_NUMERIC_OPS_F32_REINTERPRET_I32 + :source_file: crates/herkos-tests/tests/numeric_ops.rs + :tags: numeric_ops + :verifies: WASM_I64_DIV_S, WASM_I64_AND, WASM_I64_SHL, WASM_I64_LT_S, WASM_I64_CLZ, WASM_I64_ROTL, WASM_I64_REM_U, WASM_F64_DIV, WASM_F64_MIN, WASM_F64_LT, WASM_F64_SQRT, WASM_F64_FLOOR, WASM_F64_CEIL, WASM_F64_NEG, WASM_I32_WRAP_I64, WASM_I64_EXTEND_I32_S, WASM_I64_EXTEND_I32_U, WASM_EXEC_INTEGER_OPS, WASM_EXEC_FLOAT_OPS, WASM_EXEC_CONVERSIONS + + ``test_f32_reinterpret_i32`` in ``crates/herkos-tests/tests/numeric_ops.rs``. + +rust_e2e +-------- + +.. test:: test_add_i32 + :id: TEST_RUST_E2E_ADD_I32 + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i32`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_add_i32_wrapping + :id: TEST_RUST_E2E_ADD_I32_WRAPPING + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i32_wrapping`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_sub_i32 + :id: TEST_RUST_E2E_SUB_I32 + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_sub_i32`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_sub_i32_wrapping + :id: TEST_RUST_E2E_SUB_I32_WRAPPING + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_sub_i32_wrapping`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_mul_i32 + :id: TEST_RUST_E2E_MUL_I32 + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_mul_i32`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_mul_i32_wrapping + :id: TEST_RUST_E2E_MUL_I32_WRAPPING + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_mul_i32_wrapping`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_add_i64 + :id: TEST_RUST_E2E_ADD_I64 + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i64`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_add_i64_large + :id: TEST_RUST_E2E_ADD_I64_LARGE + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i64_large`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_add_i64_wrapping + :id: TEST_RUST_E2E_ADD_I64_WRAPPING + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_add_i64_wrapping`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_bitwise_and + :id: TEST_RUST_E2E_BITWISE_AND + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_and`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_bitwise_or + :id: TEST_RUST_E2E_BITWISE_OR + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_or`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_bitwise_xor + :id: TEST_RUST_E2E_BITWISE_XOR + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_bitwise_xor`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_shift_left + :id: TEST_RUST_E2E_SHIFT_LEFT + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_shift_left`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_shift_right_unsigned + :id: TEST_RUST_E2E_SHIFT_RIGHT_UNSIGNED + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_shift_right_unsigned`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_negate + :id: TEST_RUST_E2E_NEGATE + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_negate`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_negate_wrapping + :id: TEST_RUST_E2E_NEGATE_WRAPPING + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_negate_wrapping`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_const_42 + :id: TEST_RUST_E2E_CONST_42 + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_const_42`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_diff_of_squares + :id: TEST_RUST_E2E_DIFF_OF_SQUARES + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_diff_of_squares`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_matches_native_rust + :id: TEST_RUST_E2E_MATCHES_NATIVE_RUST + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_matches_native_rust`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +.. test:: test_commutative_ops + :id: TEST_RUST_E2E_COMMUTATIVE_OPS + :source_file: crates/herkos-tests/tests/rust_e2e.rs + :tags: rust_e2e + :verifies: WASM_I32_ADD, WASM_I32_SUB, WASM_I32_MUL, WASM_I32_AND, WASM_I32_OR, WASM_I32_XOR, WASM_I32_SHL, WASM_I32_SHR_U, WASM_I64_ADD, WASM_MOD_EXPORTS, WASM_MOD_FUNCTIONS + + ``test_commutative_ops`` in ``crates/herkos-tests/tests/rust_e2e.rs``. + +rust_e2e_control +---------------- + +.. test:: test_power + :id: TEST_RUST_E2E_CONTROL_POWER + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_power`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_collatz_steps + :id: TEST_RUST_E2E_CONTROL_COLLATZ_STEPS + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_collatz_steps`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_digital_root + :id: TEST_RUST_E2E_CONTROL_DIGITAL_ROOT + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_digital_root`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_gcd + :id: TEST_RUST_E2E_CONTROL_GCD + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_gcd`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_lcm + :id: TEST_RUST_E2E_CONTROL_LCM + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_lcm`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_popcount + :id: TEST_RUST_E2E_CONTROL_POPCOUNT + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_popcount`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_is_power_of_two + :id: TEST_RUST_E2E_CONTROL_IS_POWER_OF_TWO + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_is_power_of_two`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_isqrt + :id: TEST_RUST_E2E_CONTROL_ISQRT + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_isqrt`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +.. test:: test_matches_c_collatz + :id: TEST_RUST_E2E_CONTROL_MATCHES_C_COLLATZ + :source_file: crates/herkos-tests/tests/rust_e2e_control.rs + :tags: rust_e2e_control + :verifies: WASM_LOOP, WASM_BR_IF, WASM_IF, WASM_BLOCK, WASM_EXEC_CONTROL + + ``test_matches_c_collatz`` in ``crates/herkos-tests/tests/rust_e2e_control.rs``. + +rust_e2e_heavy_fibo +------------------- + +.. test:: test_fibo_base_cases + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_BASE_CASES + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_base_cases`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_fibo_small_values + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_SMALL_VALUES + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_small_values`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_fibo_matches_reference + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_MATCHES_REFERENCE + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_matches_reference`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_fibo_negative_returns_zero + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_NEGATIVE_RETURNS_ZERO + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_negative_returns_zero`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_cache_seeded_with_two_entries + :id: TEST_RUST_E2E_HEAVY_FIBO_CACHE_SEEDED_WITH_TWO_ENTRIES + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_cache_seeded_with_two_entries`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_cache_grows_to_cover_requested_index + :id: TEST_RUST_E2E_HEAVY_FIBO_CACHE_GROWS_TO_COVER_REQUESTED_INDEX + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_cache_grows_to_cover_requested_index`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_cache_extends_incrementally + :id: TEST_RUST_E2E_HEAVY_FIBO_CACHE_EXTENDS_INCREMENTALLY + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_cache_extends_incrementally`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_cache_does_not_shrink_on_smaller_query + :id: TEST_RUST_E2E_HEAVY_FIBO_CACHE_DOES_NOT_SHRINK_ON_SMALLER_QUERY + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_cache_does_not_shrink_on_smaller_query`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_cache_len_is_monotone + :id: TEST_RUST_E2E_HEAVY_FIBO_CACHE_LEN_IS_MONOTONE + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_cache_len_is_monotone`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_fibo_wrapping_overflow + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_WRAPPING_OVERFLOW + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_wrapping_overflow`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +.. test:: test_fibo_idempotent + :id: TEST_RUST_E2E_HEAVY_FIBO_FIBO_IDEMPOTENT + :source_file: crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs + :tags: rust_e2e_heavy_fibo + :verifies: WASM_CALL, WASM_I32_ADD, WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_CALLS + + ``test_fibo_idempotent`` in ``crates/herkos-tests/tests/rust_e2e_heavy_fibo.rs``. + +rust_e2e_i64 +------------ + +.. test:: test_mul_i64 + :id: TEST_RUST_E2E_I64_MUL_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_mul_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_sub_i64 + :id: TEST_RUST_E2E_I64_SUB_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_sub_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_bitwise_i64 + :id: TEST_RUST_E2E_I64_BITWISE_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_bitwise_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_shift_i64 + :id: TEST_RUST_E2E_I64_SHIFT_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_shift_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_negate_i64 + :id: TEST_RUST_E2E_I64_NEGATE_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_negate_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_fib_i64 + :id: TEST_RUST_E2E_I64_FIB_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_fib_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_factorial_i64 + :id: TEST_RUST_E2E_I64_FACTORIAL_I64 + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_factorial_i64`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_fib_matches_c + :id: TEST_RUST_E2E_I64_FIB_MATCHES_C + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_fib_matches_c`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +.. test:: test_factorial_matches_c + :id: TEST_RUST_E2E_I64_FACTORIAL_MATCHES_C + :source_file: crates/herkos-tests/tests/rust_e2e_i64.rs + :tags: rust_e2e_i64 + :verifies: WASM_I64_MUL, WASM_I64_SUB, WASM_I64_AND, WASM_I64_OR, WASM_I64_XOR, WASM_I64_SHL, WASM_I64_SHR_S + + ``test_factorial_matches_c`` in ``crates/herkos-tests/tests/rust_e2e_i64.rs``. + +rust_e2e_memory_bench +--------------------- + +.. test:: test_zero_elements_returns_zero + :id: TEST_RUST_E2E_MEMORY_BENCH_ZERO_ELEMENTS_RETURNS_ZERO + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_zero_elements_returns_zero`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_negative_n_returns_zero + :id: TEST_RUST_E2E_MEMORY_BENCH_NEGATIVE_N_RETURNS_ZERO + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_negative_n_returns_zero`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_single_element + :id: TEST_RUST_E2E_MEMORY_BENCH_SINGLE_ELEMENT + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_single_element`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_matches_reference_small_n + :id: TEST_RUST_E2E_MEMORY_BENCH_MATCHES_REFERENCE_SMALL_N + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_matches_reference_small_n`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_matches_reference_various_seeds + :id: TEST_RUST_E2E_MEMORY_BENCH_MATCHES_REFERENCE_VARIOUS_SEEDS + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_matches_reference_various_seeds`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_matches_reference_full_buffer + :id: TEST_RUST_E2E_MEMORY_BENCH_MATCHES_REFERENCE_FULL_BUFFER + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_matches_reference_full_buffer`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_n_capped_at_1024 + :id: TEST_RUST_E2E_MEMORY_BENCH_N_CAPPED_AT_1024 + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_n_capped_at_1024`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_buffer_is_sorted_after_call + :id: TEST_RUST_E2E_MEMORY_BENCH_BUFFER_IS_SORTED_AFTER_CALL + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_buffer_is_sorted_after_call`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_deterministic_across_calls + :id: TEST_RUST_E2E_MEMORY_BENCH_DETERMINISTIC_ACROSS_CALLS + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_deterministic_across_calls`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +.. test:: test_sequential_calls_independent + :id: TEST_RUST_E2E_MEMORY_BENCH_SEQUENTIAL_CALLS_INDEPENDENT + :source_file: crates/herkos-tests/tests/rust_e2e_memory_bench.rs + :tags: rust_e2e_memory_bench + :verifies: WASM_I32_LOAD, WASM_I32_STORE, WASM_EXEC_MEMORY + + ``test_sequential_calls_independent`` in ``crates/herkos-tests/tests/rust_e2e_memory_bench.rs``. + +select +------ + +.. test:: test_max_first_larger + :id: TEST_SELECT_MAX_FIRST_LARGER + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_max_first_larger`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_max_second_larger + :id: TEST_SELECT_MAX_SECOND_LARGER + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_max_second_larger`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_max_equal + :id: TEST_SELECT_MAX_EQUAL + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_max_equal`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_max_negative + :id: TEST_SELECT_MAX_NEGATIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_max_negative`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_min_first_smaller + :id: TEST_SELECT_MIN_FIRST_SMALLER + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_min_first_smaller`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_min_second_smaller + :id: TEST_SELECT_MIN_SECOND_SMALLER + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_min_second_smaller`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_min_equal + :id: TEST_SELECT_MIN_EQUAL + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_min_equal`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_min_negative + :id: TEST_SELECT_MIN_NEGATIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_min_negative`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_abs_positive + :id: TEST_SELECT_ABS_POSITIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_abs_positive`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_abs_negative + :id: TEST_SELECT_ABS_NEGATIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_abs_negative`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_abs_zero + :id: TEST_SELECT_ABS_ZERO + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_abs_zero`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_clamp_positive + :id: TEST_SELECT_CLAMP_POSITIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_clamp_positive`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_clamp_negative + :id: TEST_SELECT_CLAMP_NEGATIVE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_clamp_negative`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_clamp_zero + :id: TEST_SELECT_CLAMP_ZERO + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_clamp_zero`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_cond_inc_true + :id: TEST_SELECT_COND_INC_TRUE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_cond_inc_true`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_cond_inc_false + :id: TEST_SELECT_COND_INC_FALSE + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_cond_inc_false`` in ``crates/herkos-tests/tests/select.rs``. + +.. test:: test_cond_inc_nonzero_flag + :id: TEST_SELECT_COND_INC_NONZERO_FLAG + :source_file: crates/herkos-tests/tests/select.rs + :tags: select + :verifies: WASM_SELECT, WASM_EXEC_PARAMETRIC + + ``test_cond_inc_nonzero_flag`` in ``crates/herkos-tests/tests/select.rs``. + +subwidth_mem +------------ + +.. test:: test_store_load_byte_unsigned + :id: TEST_SUBWIDTH_MEM_STORE_LOAD_BYTE_UNSIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_load_byte_unsigned`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_load_byte_signed + :id: TEST_SUBWIDTH_MEM_STORE_LOAD_BYTE_SIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_load_byte_signed`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_load_byte_positive + :id: TEST_SUBWIDTH_MEM_STORE_LOAD_BYTE_POSITIVE + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_load_byte_positive`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_byte_truncates + :id: TEST_SUBWIDTH_MEM_STORE_BYTE_TRUNCATES + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_byte_truncates`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_load_i16_unsigned + :id: TEST_SUBWIDTH_MEM_STORE_LOAD_I16_UNSIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_load_i16_unsigned`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_load_i16_signed + :id: TEST_SUBWIDTH_MEM_STORE_LOAD_I16_SIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_load_i16_signed`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_store_i16_truncates + :id: TEST_SUBWIDTH_MEM_STORE_I16_TRUNCATES + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_store_i16_truncates`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_i64_store_load_byte_unsigned + :id: TEST_SUBWIDTH_MEM_I64_STORE_LOAD_BYTE_UNSIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_i64_store_load_byte_unsigned`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_i64_store_load_byte_signed + :id: TEST_SUBWIDTH_MEM_I64_STORE_LOAD_BYTE_SIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_i64_store_load_byte_signed`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_i64_store32_load32_unsigned + :id: TEST_SUBWIDTH_MEM_I64_STORE32_LOAD32_UNSIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_i64_store32_load32_unsigned`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_i64_store32_load32_signed + :id: TEST_SUBWIDTH_MEM_I64_STORE32_LOAD32_SIGNED + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_i64_store32_load32_signed`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +.. test:: test_i64_store32_positive + :id: TEST_SUBWIDTH_MEM_I64_STORE32_POSITIVE + :source_file: crates/herkos-tests/tests/subwidth_mem.rs + :tags: subwidth_mem + :verifies: WASM_I32_LOAD8_S, WASM_I32_LOAD8_U, WASM_I32_LOAD16_S, WASM_I32_LOAD16_U, WASM_I32_STORE8, WASM_I32_STORE16, WASM_I64_LOAD8_S, WASM_I64_LOAD8_U, WASM_I64_LOAD32_S, WASM_I64_LOAD32_U, WASM_I64_STORE32 + + ``test_i64_store32_positive`` in ``crates/herkos-tests/tests/subwidth_mem.rs``. + +unreachable +----------- + +.. test:: test_always_traps + :id: TEST_UNREACHABLE_ALWAYS_TRAPS + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_always_traps`` in ``crates/herkos-tests/tests/unreachable.rs``. + +.. test:: test_trap_on_zero + :id: TEST_UNREACHABLE_TRAP_ON_ZERO + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_trap_on_zero`` in ``crates/herkos-tests/tests/unreachable.rs``. + +.. test:: test_no_trap_on_nonzero + :id: TEST_UNREACHABLE_NO_TRAP_ON_NONZERO + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_no_trap_on_nonzero`` in ``crates/herkos-tests/tests/unreachable.rs``. + +.. test:: test_safe_div_normal + :id: TEST_UNREACHABLE_SAFE_DIV_NORMAL + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_safe_div_normal`` in ``crates/herkos-tests/tests/unreachable.rs``. + +.. test:: test_safe_div_traps_on_zero + :id: TEST_UNREACHABLE_SAFE_DIV_TRAPS_ON_ZERO + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_safe_div_traps_on_zero`` in ``crates/herkos-tests/tests/unreachable.rs``. + +.. test:: test_dead_unreachable + :id: TEST_UNREACHABLE_DEAD_UNREACHABLE + :source_file: crates/herkos-tests/tests/unreachable.rs + :tags: unreachable + :verifies: WASM_UNREACHABLE, WASM_EXEC_CONTROL + + ``test_dead_unreachable`` in ``crates/herkos-tests/tests/unreachable.rs``. diff --git a/docs/traceability/wasm_spec/binary.md b/docs/traceability/wasm_spec/binary.md new file mode 100644 index 0000000..52d5117 --- /dev/null +++ b/docs/traceability/wasm_spec/binary.md @@ -0,0 +1,44 @@ +# Binary Format + +Wasm 1.0 binary format (§5). + +Source: [W3C WebAssembly Core Specification 1.0, §5](https://www.w3.org/TR/wasm-core-1/#binary-format%E2%91%A0) + +```{wasm_spec} Binary type encoding +:id: WASM_BIN_TYPES +:wasm_section: §5.3 +:tags: binary, types + +Wasm 1.0 §5.3: Binary encoding of types — value types (0x7F=i32, 0x7E=i64, +0x7D=f32, 0x7C=f64), function types (0x60 prefix), limits, memory types, +table types, global types. +``` + +```{wasm_spec} Binary instruction encoding +:id: WASM_BIN_INSTRUCTIONS +:wasm_section: §5.4 +:tags: binary, instructions + +Wasm 1.0 §5.4: Binary encoding of instructions — single-byte opcodes (0x00 +through 0xBF), memarg encoding (alignment + offset), block type encoding, +br_table encoding. +``` + +```{wasm_spec} Binary module encoding +:id: WASM_BIN_MODULES +:wasm_section: §5.5 +:tags: binary, module + +Wasm 1.0 §5.5: Binary encoding of the module structure — magic number +(0x00 0x61 0x73 0x6D), version (0x01), section-based layout. +``` + +```{wasm_spec} Binary section encoding +:id: WASM_BIN_SECTIONS +:wasm_section: §5.5.2 +:tags: binary, module, sections + +Wasm 1.0 §5.5.2: Encoding of the 12 known section types: custom (0), type (1), +import (2), function (3), table (4), memory (5), global (6), export (7), +start (8), element (9), code (10), data (11). Sections must appear in order. +``` diff --git a/docs/traceability/wasm_spec/execution.md b/docs/traceability/wasm_spec/execution.md new file mode 100644 index 0000000..cfd0ccc --- /dev/null +++ b/docs/traceability/wasm_spec/execution.md @@ -0,0 +1,107 @@ +# Execution + +Wasm 1.0 execution semantics (§4). + +Source: [W3C WebAssembly Core Specification 1.0, §4](https://www.w3.org/TR/wasm-core-1/#execution%E2%91%A0) + +## Numerics (§4.3) + +```{wasm_spec} Integer operations semantics +:id: WASM_EXEC_INTEGER_OPS +:wasm_section: §4.3.2 +:tags: execution, numeric, integer + +Wasm 1.0 §4.3.2: Execution semantics for integer operations — wrapping +arithmetic, signed/unsigned division (trapping on zero or overflow), shifts, +rotations, comparisons, and test (eqz). +``` + +```{wasm_spec} Floating-point operations semantics +:id: WASM_EXEC_FLOAT_OPS +:wasm_section: §4.3.3 +:tags: execution, numeric, float + +Wasm 1.0 §4.3.3: Execution semantics for floating-point operations following +IEEE 754 — arithmetic, min/max, sqrt, rounding, comparisons. NaN propagation +per the Wasm spec's deterministic NaN rules. +``` + +```{wasm_spec} Conversion operations semantics +:id: WASM_EXEC_CONVERSIONS +:wasm_section: §4.3.4 +:tags: execution, numeric, conversion + +Wasm 1.0 §4.3.4: Execution semantics for type conversions — truncation +(trapping on NaN/overflow), extension, wrapping, promotion, demotion, +reinterpretation (bitcast). +``` + +## Instructions (§4.4) + +```{wasm_spec} Parametric instruction execution +:id: WASM_EXEC_PARAMETRIC +:wasm_section: §4.4.2 +:tags: execution, parametric + +Wasm 1.0 §4.4.2: Execution of `drop` (discard top of stack) and `select` +(ternary selection based on i32 condition). +``` + +```{wasm_spec} Variable instruction execution +:id: WASM_EXEC_VARIABLE +:wasm_section: §4.4.3 +:tags: execution, variable + +Wasm 1.0 §4.4.3: Execution of `local.get`, `local.set`, `local.tee`, +`global.get`, `global.set` — reading and writing locals and globals. +``` + +```{wasm_spec} Memory instruction execution +:id: WASM_EXEC_MEMORY +:wasm_section: §4.4.4 +:tags: execution, memory + +Wasm 1.0 §4.4.4: Execution of memory instructions — load/store with +effective address = base + offset, trapping on out-of-bounds. Sub-width +access with sign/zero extension. `memory.size` and `memory.grow`. +``` + +```{wasm_spec} Control instruction execution +:id: WASM_EXEC_CONTROL +:wasm_section: §4.4.5 +:tags: execution, control + +Wasm 1.0 §4.4.5: Execution of control instructions — block entry/exit, branch +resolution, label unwinding, `unreachable` trap, `nop`. +``` + +```{wasm_spec} Function call execution +:id: WASM_EXEC_CALLS +:wasm_section: §4.4.7 +:tags: execution, call + +Wasm 1.0 §4.4.7: Execution of `call` (direct) and `call_indirect` (via table +with type check). Frame push/pop, argument passing, result collection. Traps +on type mismatch or undefined table element. +``` + +## Modules (§4.5) + +```{wasm_spec} Module instantiation +:id: WASM_EXEC_INSTANTIATION +:wasm_section: §4.5.4 +:tags: execution, module, instantiation + +Wasm 1.0 §4.5.4: Module instantiation — allocating functions, tables, memories, +globals; initializing tables from element segments and memories from data +segments; invoking the start function. +``` + +```{wasm_spec} Function invocation +:id: WASM_EXEC_INVOCATION +:wasm_section: §4.5.5 +:tags: execution, module, invocation + +Wasm 1.0 §4.5.5: Invocation of an exported function from the host — argument +validation, frame creation, body execution, result extraction. +``` diff --git a/docs/traceability/wasm_spec/index.rst b/docs/traceability/wasm_spec/index.rst new file mode 100644 index 0000000..02d78d7 --- /dev/null +++ b/docs/traceability/wasm_spec/index.rst @@ -0,0 +1,17 @@ +WebAssembly 1.0 Specification +============================= + +Traceable needs derived from the +`W3C WebAssembly Core Specification 1.0 `_ +(W3C Recommendation, December 5, 2019). + +.. toctree:: + :maxdepth: 2 + + types + _gen/instructions_numeric + instructions_other + modules + validation + execution + binary diff --git a/docs/traceability/wasm_spec/instructions_other.md b/docs/traceability/wasm_spec/instructions_other.md new file mode 100644 index 0000000..75fe2d8 --- /dev/null +++ b/docs/traceability/wasm_spec/instructions_other.md @@ -0,0 +1,419 @@ +# Non-Numeric Instructions + +Wasm 1.0 parametric, variable, memory, and control instructions. + +## Parametric Instructions (§2.4.2) + +Source: [W3C WebAssembly Core Specification 1.0, §2.4.2](https://www.w3.org/TR/wasm-core-1/#parametric-instructions%E2%91%A0) + +```{wasm_spec} drop +:id: WASM_DROP +:wasm_section: §2.4.2 +:wasm_opcode: drop +:tags: parametric + +Wasm 1.0: `drop` — discard a single operand from the stack. +``` + +```{wasm_spec} select +:id: WASM_SELECT +:wasm_section: §2.4.2 +:wasm_opcode: select +:tags: parametric + +Wasm 1.0: `select` — choose between two operands based on a condition. +``` + +## Variable Instructions (§2.4.3) + +Source: [W3C WebAssembly Core Specification 1.0, §2.4.3](https://www.w3.org/TR/wasm-core-1/#variable-instructions%E2%91%A0) + +```{wasm_spec} local.get +:id: WASM_LOCAL_GET +:wasm_section: §2.4.3 +:wasm_opcode: local.get +:tags: variable, local + +Wasm 1.0: `local.get` — read a local variable. +``` + +```{wasm_spec} local.set +:id: WASM_LOCAL_SET +:wasm_section: §2.4.3 +:wasm_opcode: local.set +:tags: variable, local + +Wasm 1.0: `local.set` — write a local variable. +``` + +```{wasm_spec} local.tee +:id: WASM_LOCAL_TEE +:wasm_section: §2.4.3 +:wasm_opcode: local.tee +:tags: variable, local + +Wasm 1.0: `local.tee` — write a local variable and return the value. +``` + +```{wasm_spec} global.get +:id: WASM_GLOBAL_GET +:wasm_section: §2.4.3 +:wasm_opcode: global.get +:tags: variable, global + +Wasm 1.0: `global.get` — read a global variable. +``` + +```{wasm_spec} global.set +:id: WASM_GLOBAL_SET +:wasm_section: §2.4.3 +:wasm_opcode: global.set +:tags: variable, global + +Wasm 1.0: `global.set` — write a mutable global variable. +``` + +## Memory Instructions (§2.4.4) + +Source: [W3C WebAssembly Core Specification 1.0, §2.4.4](https://www.w3.org/TR/wasm-core-1/#memory-instructions%E2%91%A0) + +### Loads + +```{wasm_spec} i32.load +:id: WASM_I32_LOAD +:wasm_section: §2.4.4 +:wasm_opcode: i32.load +:tags: memory, load, i32 + +Wasm 1.0: `i32.load` — load 32-bit integer from linear memory. +``` + +```{wasm_spec} i64.load +:id: WASM_I64_LOAD +:wasm_section: §2.4.4 +:wasm_opcode: i64.load +:tags: memory, load, i64 + +Wasm 1.0: `i64.load` — load 64-bit integer from linear memory. +``` + +```{wasm_spec} f32.load +:id: WASM_F32_LOAD +:wasm_section: §2.4.4 +:wasm_opcode: f32.load +:tags: memory, load, f32 + +Wasm 1.0: `f32.load` — load 32-bit float from linear memory. +``` + +```{wasm_spec} f64.load +:id: WASM_F64_LOAD +:wasm_section: §2.4.4 +:wasm_opcode: f64.load +:tags: memory, load, f64 + +Wasm 1.0: `f64.load` — load 64-bit float from linear memory. +``` + +### Sub-width Loads + +```{wasm_spec} i32.load8_s +:id: WASM_I32_LOAD8_S +:wasm_section: §2.4.4 +:wasm_opcode: i32.load8_s +:tags: memory, load, i32, subwidth + +Wasm 1.0: `i32.load8_s` — load 8-bit value, sign-extend to i32. +``` + +```{wasm_spec} i32.load8_u +:id: WASM_I32_LOAD8_U +:wasm_section: §2.4.4 +:wasm_opcode: i32.load8_u +:tags: memory, load, i32, subwidth + +Wasm 1.0: `i32.load8_u` — load 8-bit value, zero-extend to i32. +``` + +```{wasm_spec} i32.load16_s +:id: WASM_I32_LOAD16_S +:wasm_section: §2.4.4 +:wasm_opcode: i32.load16_s +:tags: memory, load, i32, subwidth + +Wasm 1.0: `i32.load16_s` — load 16-bit value, sign-extend to i32. +``` + +```{wasm_spec} i32.load16_u +:id: WASM_I32_LOAD16_U +:wasm_section: §2.4.4 +:wasm_opcode: i32.load16_u +:tags: memory, load, i32, subwidth + +Wasm 1.0: `i32.load16_u` — load 16-bit value, zero-extend to i32. +``` + +```{wasm_spec} i64.load8_s +:id: WASM_I64_LOAD8_S +:wasm_section: §2.4.4 +:wasm_opcode: i64.load8_s +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load8_s` — load 8-bit value, sign-extend to i64. +``` + +```{wasm_spec} i64.load8_u +:id: WASM_I64_LOAD8_U +:wasm_section: §2.4.4 +:wasm_opcode: i64.load8_u +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load8_u` — load 8-bit value, zero-extend to i64. +``` + +```{wasm_spec} i64.load16_s +:id: WASM_I64_LOAD16_S +:wasm_section: §2.4.4 +:wasm_opcode: i64.load16_s +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load16_s` — load 16-bit value, sign-extend to i64. +``` + +```{wasm_spec} i64.load16_u +:id: WASM_I64_LOAD16_U +:wasm_section: §2.4.4 +:wasm_opcode: i64.load16_u +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load16_u` — load 16-bit value, zero-extend to i64. +``` + +```{wasm_spec} i64.load32_s +:id: WASM_I64_LOAD32_S +:wasm_section: §2.4.4 +:wasm_opcode: i64.load32_s +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load32_s` — load 32-bit value, sign-extend to i64. +``` + +```{wasm_spec} i64.load32_u +:id: WASM_I64_LOAD32_U +:wasm_section: §2.4.4 +:wasm_opcode: i64.load32_u +:tags: memory, load, i64, subwidth + +Wasm 1.0: `i64.load32_u` — load 32-bit value, zero-extend to i64. +``` + +### Stores + +```{wasm_spec} i32.store +:id: WASM_I32_STORE +:wasm_section: §2.4.4 +:wasm_opcode: i32.store +:tags: memory, store, i32 + +Wasm 1.0: `i32.store` — store 32-bit integer to linear memory. +``` + +```{wasm_spec} i64.store +:id: WASM_I64_STORE +:wasm_section: §2.4.4 +:wasm_opcode: i64.store +:tags: memory, store, i64 + +Wasm 1.0: `i64.store` — store 64-bit integer to linear memory. +``` + +```{wasm_spec} f32.store +:id: WASM_F32_STORE +:wasm_section: §2.4.4 +:wasm_opcode: f32.store +:tags: memory, store, f32 + +Wasm 1.0: `f32.store` — store 32-bit float to linear memory. +``` + +```{wasm_spec} f64.store +:id: WASM_F64_STORE +:wasm_section: §2.4.4 +:wasm_opcode: f64.store +:tags: memory, store, f64 + +Wasm 1.0: `f64.store` — store 64-bit float to linear memory. +``` + +### Sub-width Stores + +```{wasm_spec} i32.store8 +:id: WASM_I32_STORE8 +:wasm_section: §2.4.4 +:wasm_opcode: i32.store8 +:tags: memory, store, i32, subwidth + +Wasm 1.0: `i32.store8` — store low 8 bits of i32 to linear memory. +``` + +```{wasm_spec} i32.store16 +:id: WASM_I32_STORE16 +:wasm_section: §2.4.4 +:wasm_opcode: i32.store16 +:tags: memory, store, i32, subwidth + +Wasm 1.0: `i32.store16` — store low 16 bits of i32 to linear memory. +``` + +```{wasm_spec} i64.store8 +:id: WASM_I64_STORE8 +:wasm_section: §2.4.4 +:wasm_opcode: i64.store8 +:tags: memory, store, i64, subwidth + +Wasm 1.0: `i64.store8` — store low 8 bits of i64 to linear memory. +``` + +```{wasm_spec} i64.store16 +:id: WASM_I64_STORE16 +:wasm_section: §2.4.4 +:wasm_opcode: i64.store16 +:tags: memory, store, i64, subwidth + +Wasm 1.0: `i64.store16` — store low 16 bits of i64 to linear memory. +``` + +```{wasm_spec} i64.store32 +:id: WASM_I64_STORE32 +:wasm_section: §2.4.4 +:wasm_opcode: i64.store32 +:tags: memory, store, i64, subwidth + +Wasm 1.0: `i64.store32` — store low 32 bits of i64 to linear memory. +``` + +### Memory Management + +```{wasm_spec} memory.size +:id: WASM_MEMORY_SIZE +:wasm_section: §2.4.4 +:wasm_opcode: memory.size +:tags: memory, management + +Wasm 1.0: `memory.size` — return current memory size in pages. +``` + +```{wasm_spec} memory.grow +:id: WASM_MEMORY_GROW +:wasm_section: §2.4.4 +:wasm_opcode: memory.grow +:tags: memory, management + +Wasm 1.0: `memory.grow` — grow memory by delta pages, return previous size or -1. +``` + +## Control Instructions (§2.4.5) + +Source: [W3C WebAssembly Core Specification 1.0, §2.4.5](https://www.w3.org/TR/wasm-core-1/#control-instructions%E2%91%A0) + +```{wasm_spec} nop +:id: WASM_NOP +:wasm_section: §2.4.5 +:wasm_opcode: nop +:tags: control + +Wasm 1.0: `nop` — no operation. +``` + +```{wasm_spec} unreachable +:id: WASM_UNREACHABLE +:wasm_section: §2.4.5 +:wasm_opcode: unreachable +:tags: control + +Wasm 1.0: `unreachable` — cause an unconditional trap. +``` + +```{wasm_spec} block +:id: WASM_BLOCK +:wasm_section: §2.4.5 +:wasm_opcode: block +:tags: control, structured + +Wasm 1.0: `block` — begin a structured block of instructions with a label. +``` + +```{wasm_spec} loop +:id: WASM_LOOP +:wasm_section: §2.4.5 +:wasm_opcode: loop +:tags: control, structured + +Wasm 1.0: `loop` — begin a structured loop with a label (branch target is the +loop header). +``` + +```{wasm_spec} if +:id: WASM_IF +:wasm_section: §2.4.5 +:wasm_opcode: if +:tags: control, structured + +Wasm 1.0: `if` — conditional block: execute then-branch or else-branch based +on a condition. +``` + +```{wasm_spec} br +:id: WASM_BR +:wasm_section: §2.4.5 +:wasm_opcode: br +:tags: control, branch + +Wasm 1.0: `br` — unconditional branch to the label at the given depth. +``` + +```{wasm_spec} br_if +:id: WASM_BR_IF +:wasm_section: §2.4.5 +:wasm_opcode: br_if +:tags: control, branch + +Wasm 1.0: `br_if` — conditional branch: branch if the condition is non-zero. +``` + +```{wasm_spec} br_table +:id: WASM_BR_TABLE +:wasm_section: §2.4.5 +:wasm_opcode: br_table +:tags: control, branch + +Wasm 1.0: `br_table` — indirect branch via operand indexing into a table of +labels, with a default target. +``` + +```{wasm_spec} call +:id: WASM_CALL +:wasm_section: §2.4.5 +:wasm_opcode: call +:tags: control, call + +Wasm 1.0: `call` — direct function call by function index. +``` + +```{wasm_spec} call_indirect +:id: WASM_CALL_INDIRECT +:wasm_section: §2.4.5 +:wasm_opcode: call_indirect +:tags: control, call, indirect + +Wasm 1.0: `call_indirect` — indirect function call via table, with type check. +``` + +```{wasm_spec} return +:id: WASM_RETURN +:wasm_section: §2.4.5 +:wasm_opcode: return +:tags: control + +Wasm 1.0: `return` — return from the current function. +``` diff --git a/docs/traceability/wasm_spec/modules.md b/docs/traceability/wasm_spec/modules.md new file mode 100644 index 0000000..a1cbe03 --- /dev/null +++ b/docs/traceability/wasm_spec/modules.md @@ -0,0 +1,99 @@ +# Modules + +Wasm 1.0 module constructs (§2.5). + +Source: [W3C WebAssembly Core Specification 1.0, §2.5](https://www.w3.org/TR/wasm-core-1/#modules%E2%91%A0) + +```{wasm_spec} Type section +:id: WASM_MOD_TYPES +:wasm_section: §2.5.2 +:tags: module, types + +Wasm 1.0 §2.5.2: The type section defines a vector of function types used by +the module. Function signatures are referenced by type index throughout the +module. +``` + +```{wasm_spec} Functions +:id: WASM_MOD_FUNCTIONS +:wasm_section: §2.5.3 +:tags: module, function + +Wasm 1.0 §2.5.3: Functions are defined by their type, a vector of local +variable declarations, and a body (expression). Parameters are addressed +as the first locals. +``` + +```{wasm_spec} Tables +:id: WASM_MOD_TABLES +:wasm_section: §2.5.4 +:tags: module, table + +Wasm 1.0 §2.5.4: A table is a vector of opaque values of a given reference +type (`funcref` in 1.0). At most one table per module. Used for indirect calls. +``` + +```{wasm_spec} Memories +:id: WASM_MOD_MEMORIES +:wasm_section: §2.5.5 +:tags: module, memory + +Wasm 1.0 §2.5.5: A memory is a vector of raw bytes (linear memory). At most +one memory per module. Size is specified in units of page size (64 KiB). +``` + +```{wasm_spec} Globals +:id: WASM_MOD_GLOBALS +:wasm_section: §2.5.6 +:tags: module, global + +Wasm 1.0 §2.5.6: A global variable holds a single value of a given type. It +is either mutable or immutable and has a constant initializer expression. +``` + +```{wasm_spec} Element segments +:id: WASM_MOD_ELEM +:wasm_section: §2.5.7 +:tags: module, table, element + +Wasm 1.0 §2.5.7: Element segments initialize table ranges with function +references. An active segment copies elements into the table during +instantiation at a given offset. +``` + +```{wasm_spec} Data segments +:id: WASM_MOD_DATA +:wasm_section: §2.5.8 +:tags: module, memory, data + +Wasm 1.0 §2.5.8: Data segments initialize memory ranges with byte data. An +active segment copies bytes into linear memory during instantiation at a given +offset. +``` + +```{wasm_spec} Start function +:id: WASM_MOD_START +:wasm_section: §2.5.9 +:tags: module, start + +Wasm 1.0 §2.5.9: The start component declares a function index that is +automatically invoked after instantiation, before any exports become accessible. +``` + +```{wasm_spec} Exports +:id: WASM_MOD_EXPORTS +:wasm_section: §2.5.10 +:tags: module, export + +Wasm 1.0 §2.5.10: Exports make functions, tables, memories, or globals +accessible to the host environment under unique string names. +``` + +```{wasm_spec} Imports +:id: WASM_MOD_IMPORTS +:wasm_section: §2.5.11 +:tags: module, import + +Wasm 1.0 §2.5.11: Imports declare functions, tables, memories, or globals +provided by the host environment, identified by a two-level name (module, name). +``` diff --git a/docs/traceability/wasm_spec/types.md b/docs/traceability/wasm_spec/types.md new file mode 100644 index 0000000..c09765a --- /dev/null +++ b/docs/traceability/wasm_spec/types.md @@ -0,0 +1,105 @@ +# Types + +Wasm 1.0 type constructs (§2.3). + +Source: [W3C WebAssembly Core Specification 1.0, §2.3](https://www.w3.org/TR/wasm-core-1/#types%E2%91%A0) + +## Value Types + +```{wasm_spec} Value type i32 +:id: WASM_VALTYPE_I32 +:wasm_section: §2.3.1 +:tags: type, valtype, i32 + +Wasm 1.0 §2.3.1: 32-bit integer value type. +``` + +```{wasm_spec} Value type i64 +:id: WASM_VALTYPE_I64 +:wasm_section: §2.3.1 +:tags: type, valtype, i64 + +Wasm 1.0 §2.3.1: 64-bit integer value type. +``` + +```{wasm_spec} Value type f32 +:id: WASM_VALTYPE_F32 +:wasm_section: §2.3.1 +:tags: type, valtype, f32 + +Wasm 1.0 §2.3.1: 32-bit IEEE 754 floating-point value type. +``` + +```{wasm_spec} Value type f64 +:id: WASM_VALTYPE_F64 +:wasm_section: §2.3.1 +:tags: type, valtype, f64 + +Wasm 1.0 §2.3.1: 64-bit IEEE 754 floating-point value type. +``` + +## Composite Types + +```{wasm_spec} Result types +:id: WASM_RESULT_TYPE +:wasm_section: §2.3.2 +:tags: type, result + +Wasm 1.0 §2.3.2: Result types classify the result of executing instructions +or blocks, as a sequence of values. In Wasm 1.0, at most one result value is +permitted. +``` + +```{wasm_spec} Function types +:id: WASM_FUNC_TYPE +:wasm_section: §2.3.3 +:tags: type, function + +Wasm 1.0 §2.3.3: Function types classify the signature of functions, mapping a +vector of parameter types to a vector of result types (at most one in 1.0). +``` + +```{wasm_spec} Limits +:id: WASM_LIMITS +:wasm_section: §2.3.4 +:tags: type, limits + +Wasm 1.0 §2.3.4: Limits classify the size range of resizeable storage +(memories and tables), with a required minimum and optional maximum. +``` + +```{wasm_spec} Memory types +:id: WASM_MEMORY_TYPE +:wasm_section: §2.3.5 +:tags: type, memory + +Wasm 1.0 §2.3.5: Memory types classify linear memories and their size range, +specified in units of page size (64 KiB). +``` + +```{wasm_spec} Table types +:id: WASM_TABLE_TYPE +:wasm_section: §2.3.6 +:tags: type, table + +Wasm 1.0 §2.3.6: Table types classify tables over elements of reference type +within a size range. In Wasm 1.0, the only element type is `funcref`. +``` + +```{wasm_spec} Global types +:id: WASM_GLOBAL_TYPE +:wasm_section: §2.3.7 +:tags: type, global + +Wasm 1.0 §2.3.7: Global types classify global variables, which hold a value +of the given value type and can either be mutable or immutable. +``` + +```{wasm_spec} External types +:id: WASM_EXTERNAL_TYPE +:wasm_section: §2.3.8 +:tags: type, external + +Wasm 1.0 §2.3.8: External types classify imports and external values with +their respective types (function, table, memory, global). +``` diff --git a/docs/traceability/wasm_spec/validation.md b/docs/traceability/wasm_spec/validation.md new file mode 100644 index 0000000..0d84bf8 --- /dev/null +++ b/docs/traceability/wasm_spec/validation.md @@ -0,0 +1,100 @@ +# Validation + +Wasm 1.0 validation rules (§3). + +Source: [W3C WebAssembly Core Specification 1.0, §3](https://www.w3.org/TR/wasm-core-1/#validation%E2%91%A0) + +## Instruction Validation (§3.3) + +```{wasm_spec} Numeric instruction validation +:id: WASM_VALID_NUMERIC +:wasm_section: §3.3.1 +:tags: validation, numeric + +Wasm 1.0 §3.3.1: Typing rules for numeric instructions — each instruction +consumes and produces values of specific types on the operand stack. +``` + +```{wasm_spec} Parametric instruction validation +:id: WASM_VALID_PARAMETRIC +:wasm_section: §3.3.2 +:tags: validation, parametric + +Wasm 1.0 §3.3.2: Typing rules for `drop` and `select`. `select` is +value-polymorphic (operand type unconstrained). +``` + +```{wasm_spec} Variable instruction validation +:id: WASM_VALID_VARIABLE +:wasm_section: §3.3.3 +:tags: validation, variable + +Wasm 1.0 §3.3.3: Typing rules for local and global variable instructions. +Validates type consistency with the context's local/global declarations. +``` + +```{wasm_spec} Memory instruction validation +:id: WASM_VALID_MEMORY +:wasm_section: §3.3.4 +:tags: validation, memory + +Wasm 1.0 §3.3.4: Typing rules for memory instructions. Validates that a memory +exists (index 0), and that alignment is within bounds for the access width. +``` + +```{wasm_spec} Control instruction validation +:id: WASM_VALID_CONTROL +:wasm_section: §3.3.5 +:tags: validation, control + +Wasm 1.0 §3.3.5: Typing rules for control instructions. Validates block/loop/if +types, branch target label depths, and call type signatures. +``` + +## Module Validation (§3.4) + +```{wasm_spec} Function validation +:id: WASM_VALID_FUNCTIONS +:wasm_section: §3.4.1 +:tags: validation, function + +Wasm 1.0 §3.4.1: A function is valid when its body expression is valid under +a context with the function's locals and the expected result type. +``` + +```{wasm_spec} Table validation +:id: WASM_VALID_TABLES +:wasm_section: §3.4.2 +:tags: validation, table + +Wasm 1.0 §3.4.2: A table definition is valid when its type is valid +(limits within range, element type is funcref). +``` + +```{wasm_spec} Memory validation +:id: WASM_VALID_MEMORIES +:wasm_section: §3.4.3 +:tags: validation, memory + +Wasm 1.0 §3.4.3: A memory definition is valid when its type is valid +(limits within the maximum page count of 65536). +``` + +```{wasm_spec} Global validation +:id: WASM_VALID_GLOBALS +:wasm_section: §3.4.4 +:tags: validation, global + +Wasm 1.0 §3.4.4: A global definition is valid when its initializer expression +is a constant expression of the declared type. +``` + +```{wasm_spec} Module validation +:id: WASM_VALID_MODULE +:wasm_section: §3.4.10 +:tags: validation, module + +Wasm 1.0 §3.4.10: A module is valid when all its components are valid and +cross-component constraints are met (at most one memory, at most one table, +export names are unique, start function type is [] -> []). +``` diff --git a/docs/ubproject.toml b/docs/ubproject.toml new file mode 100644 index 0000000..7fd7c49 --- /dev/null +++ b/docs/ubproject.toml @@ -0,0 +1,66 @@ +"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json" + +[project] +name = "herkos" + +[needs] +id_regex = "^[A-Z][A-Z0-9_]+" + +[[needs.types]] +directive = "wasm_spec" +title = "Wasm Spec" +prefix = "WASM_" +color = "#9DC3E6" +style = "node" + +[[needs.types]] +directive = "req" +title = "Requirement" +prefix = "REQ_" +color = "#A9D18E" +style = "node" + +[[needs.types]] +directive = "spec" +title = "Specification" +prefix = "SPEC_" +color = "#FFD966" +style = "node" + +[[needs.types]] +directive = "impl" +title = "Implementation" +prefix = "IMPL_" +color = "#F4B183" +style = "node" + +[[needs.types]] +directive = "test" +title = "Test" +prefix = "TEST_" +color = "#C5B0D5" +style = "node" + +[needs.fields.wasm_section] +default = "" +description = "Wasm spec section reference" + +[needs.fields.source_file] +default = "" +description = "Source file path" + +[needs.fields.wasm_opcode] +default = "" +description = "Wasm opcode name" + +[needs.links.satisfies] +incoming = "is_satisfied_by" +copy = false + +[needs.links.implements] +incoming = "is_implemented_by" +copy = false + +[needs.links.verifies] +incoming = "is_verified_by" +copy = false