Skip to content

Commit bebcb34

Browse files
authored
Merge pull request #24 from arnoox/release/v0.2.0
Release/v0.2.0
2 parents 9d192ea + c148f23 commit bebcb34

17 files changed

Lines changed: 739 additions & 35 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,8 @@ jobs:
4949
- name: Example (C → Wasm → Rust)
5050
run: ./examples/c-to-wasm-to-rust/run.sh
5151

52+
- name: Example FFT (C → Wasm → Rust)
53+
run: ./examples/c-fft/run.sh
54+
5255
- name: Example (Inter-Module Lending)
5356
run: ./examples/inter-module-lending/run.sh

CHANGELOG.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,45 @@ All notable changes to the herkos project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [Unreleased]
8+
## [0.2.0]
99

1010
### Added
11-
- Pre-open-source code review and cleanup
12-
- Apache-2.0 license
13-
- Community files (CONTRIBUTING.md, CHANGELOG.md)
14-
- Cargo.toml metadata for all crates
15-
- GitHub issue and PR templates
11+
- Bulk memory operations: `memory.fill`, `memory.init`, `data.drop`
12+
- Version info in generated code and module metadata
13+
- Inter-module lending tests and examples with automation scripts
14+
- Memory-intensive benchmarks (sorting, Fibonacci implementations)
15+
- New benchmarks for control flow and arithmetic operations
16+
- Optimization control via `HERKOS_OPTIMIZE` environment variable
17+
18+
### Changed
19+
- Memory operations now use `usize` for better type safety
20+
- Refactored host import handling with uniform `Env<H>` API pattern
21+
- Enhanced SSA IR with improved phi-node lowering and branch resolution
22+
- Improved dead code handling in IR builder with live-check methods for terminators
23+
- Restructured `ControlFrame` enum for better control flow handling
24+
- Simplified data segment parsing using zip for segment indexing
1625

1726
### Fixed
18-
- i32 shift operations now correctly mask shift amounts to 5 bits (& 31) per WebAssembly spec
19-
- Replaced panic-inducing `unwrap()` calls in IR builder with proper error handling
20-
- Changed constructor panics to `Result` types for proper no_std compliance
27+
- Host parameter now properly handled in `call_indirect` dispatch (issue #19)
28+
- Host parameter now transitively propagated through direct calls (issue #19)
29+
- IR now enforces strict SSA form at compile time with `UseVar`/`DefVar` typing
30+
- Removed panic for unoptimizations in transpile function
31+
- Removed unnecessary crate-type configurations from Cargo.toml
32+
33+
### Removed
34+
- Example C usage and header files from repository
35+
- Herkos-bootstrap example implementation
36+
37+
## [0.1.1] - 2026-03-09
38+
39+
### Fixed
40+
- Improved diagram formatting in README.md
41+
- Updated .gitignore to include Cargo.lock
42+
- Removed unused CLI options
43+
- Updated repository and homepage URLs
44+
45+
### Added
46+
- C to WebAssembly example with Rust transpilation
2147

2248
## [0.1.0] - 2026-02-16
2349

@@ -72,7 +98,9 @@ See [docs/FUTURE.md](docs/FUTURE.md) for planned features.
7298

7399
## Version History
74100

101+
- **0.1.1** (2026-03-09) — C integration example and URL updates
75102
- **0.1.0** (2026-02-16) — Initial release with safe backend, basic transpilation, and import/export support
76103

77-
[Unreleased]: https://github.com/YOUR_ORG/herkos/compare/v0.1.0...HEAD
104+
[Unreleased]: https://github.com/YOUR_ORG/herkos/compare/v0.1.1...HEAD
105+
[0.1.1]: https://github.com/YOUR_ORG/herkos/compare/v0.1.0...v0.1.1
78106
[0.1.0]: https://github.com/YOUR_ORG/herkos/releases/tag/v0.1.0

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ resolver = "2"
33
members = ["crates/herkos-runtime", "crates/herkos-core", "crates/herkos", "crates/herkos-tests"]
44

55
exclude = [
6+
"examples/c-fft",
67
"examples/c-to-wasm-to-rust",
78
"examples/inter-module-lending",
89
"examples/herkos-bootstrap",

crates/herkos-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "herkos-core"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
edition = "2021"
55
description = "Compile-Time Memory Isolation via WebAssembly and Rust Transpilation — core library"
66
license = "Apache-2.0"

crates/herkos-runtime/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "herkos-runtime"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
edition = "2021"
55
description = "Runtime library for herkos transpiled output — IsolatedMemory, WasmTrap, capability traits"
66
license = "Apache-2.0"

crates/herkos-tests/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "herkos-tests"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55
publish = false
66
description = "End-to-end compilation tests for herkos transpiler"
@@ -13,7 +13,7 @@ herkos-runtime = { path = "../herkos-runtime" }
1313
[build-dependencies]
1414
anyhow = { workspace = true }
1515
wat = { workspace = true }
16-
herkos-core = { path = "../herkos-core" }
16+
herkos-core = { version = "0.2.0", path = "../herkos-core" }
1717

1818
[dev-dependencies]
1919
criterion = "0.8.2"

crates/herkos/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "herkos"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
edition = "2021"
55
description = "Compile-Time Memory Isolation via WebAssembly and Rust Transpilation"
66
license = "Apache-2.0"
@@ -12,7 +12,7 @@ categories = ["wasm", "development-tools::build-utils"]
1212
readme = "../../README.md"
1313

1414
[dependencies]
15-
herkos-core = { path = "../herkos-core" }
15+
herkos-core = { version = "0.2.0", path = "../herkos-core" }
1616
anyhow = { workspace = true }
1717
clap = { workspace = true }
1818

docs/REQUIREMENTS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,23 @@ memory.grow shall not perform heap allocation. New pages shall be zero-initializ
8888
within pre-allocated storage. Returns previous page count on success, -1 on failure.
8989
```
9090

91+
```{req} Bulk Memory Operations
92+
:id: REQ_MEM_BULK_OPS
93+
:status: open
94+
:tags: memory, bulk-operations, wasm-spec
95+
The transpiler shall support WebAssembly bulk memory operations: memory.fill,
96+
memory.init, and data.drop. All operations shall be bounds-checked. Out-of-bounds
97+
operations shall trap with WasmTrap::OutOfBounds, never panic.
98+
```
99+
100+
```{req} Data Segment Support
101+
:id: REQ_MEM_DATA_SEGMENTS
102+
:status: open
103+
:tags: memory, data-segments
104+
Passive data segments shall be stored as compile-time constants in the generated
105+
output. memory.init shall copy from these constants into the module's linear memory.
106+
```
107+
91108
### 4.2 Module Representation
92109

93110
```{req} Two Module Types
@@ -199,6 +216,15 @@ shall be formatted (rustfmt), readable, and auditable. No panics, no unwinding
199216
only Result<T, WasmTrap> for error handling.
200217
```
201218

219+
```{req} Version Information in Generated Code
220+
:id: REQ_TRANS_VERSION_INFO
221+
:status: open
222+
:tags: transpilation, output, metadata
223+
Generated code shall include version information: the herkos transpiler version
224+
and the WebAssembly binary format version. This enables traceability and debugging
225+
of transpiled modules.
226+
```
227+
202228
```{req} Deterministic Code Generation
203229
:id: REQ_TRANS_DETERMINISTIC
204230
:status: open

docs/SPECIFICATION.md

Lines changed: 122 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Where the requirements say *what* the system must do, this specification says *h
66

77
For features that are planned but not yet implemented (verified/hybrid backends, temporal isolation, etc.), see [FUTURE.md](FUTURE.md).
88

9-
**Document Status**: Draft — Version 0.2 — 2026-02-25
9+
**Document Status**: Draft — Version 0.2 — 2026-03-16
1010

1111
---
1212

@@ -49,6 +49,12 @@ herkos input.wasm --mode safe --output output.rs
4949
| `--output` | Output Rust file path | No |
5050
| `--max-pages` | Maximum memory pages when module declares no maximum | No |
5151

52+
**Environment variables:**
53+
54+
| Variable | Values | Default | Effect |
55+
|----------|--------|---------|--------|
56+
| `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. |
57+
5258
> **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.
5359
5460
### 1.3 Understanding the Output
@@ -500,27 +506,27 @@ let result = lib.call_export_transform(&mut app.memory, ptr, len)?;
500506
### 3.1 Component Overview
501507

502508
```
503-
┌─────────────────────────────────────────────────────────────────
504-
│ herkos workspace
505-
509+
┌─────────────────────────────────────────────────────────────────┐
510+
│ herkos workspace │
511+
│ │
506512
│ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
507513
│ │ herkos (CLI) │ │ herkos-runtime │ │ herkos-tests │ │
508514
│ │ ┌───────────┐ │ │ #![no_std] │ │ │ │
509515
│ │ │ Parser │ │ │ │ │ WAT/C/Rust │ │
510-
│ │ │(wasmparser)│ │ │ IsolatedMemory │ │ sources │ │
516+
│ │ │(wasmparser)│ │ │ IsolatedMemory │ │ sources │ │
511517
│ │ ├───────────┤ │ │ Table, FuncRef │ │ → .wasm │ │
512518
│ │ │ IR Builder│ │ │ Module types │ │ → transpile │ │
513-
│ │ │ (SSA-form)│ │ │ WasmTrap │ │ → test │ │
514-
│ │ ├───────────┤ │ │ Wasm ops │ │ │ │
519+
│ │ │ (SSA-form)│ │ │ WasmTrap │ │ → test │ │
520+
│ │ ├───────────┤ │ │ Wasm ops │ │ │ │
515521
│ │ │ Optimizer │ │ │ │ │ benches/ │ │
516522
│ │ ├───────────┤ │ └──────────────────┘ └────────────────┘ │
517-
│ │ │ Backend │ │
518-
│ │ │ (safe) │ │ │ depends on │ depends
523+
│ │ │ Backend │ │ ▲ │
524+
│ │ │ (safe) │ │ │ depends on │ depends
519525
│ │ ├───────────┤ │ │ │ on both │
520-
│ │ │ Codegen │ │ └─────────────────────┘
521-
│ │ └───────────┘ │
522-
│ └─────────────────┘
523-
└─────────────────────────────────────────────────────────────────
526+
│ │ │ Codegen │ │ └─────────────────────┘ │
527+
│ │ └───────────┘ │ │
528+
│ └─────────────────┘ │
529+
└─────────────────────────────────────────────────────────────────┘
524530
```
525531

526532
### 3.2 Runtime (`herkos-runtime`)
@@ -809,6 +815,61 @@ Type 2: (i32) → i32 → canonical = 2 (new signature)
809815

810816
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.
811817

818+
### 4.6 Bulk Memory Operations
819+
820+
> Implementation: [crates/herkos-runtime/src/memory.rs](../crates/herkos-runtime/src/memory.rs) lines 149–174
821+
822+
The WebAssembly bulk memory operations allow efficient copying and initialization of memory regions without scalar load/store loops.
823+
824+
#### 4.6.1 `memory.fill`
825+
826+
Fills a region of memory with a byte value. Per Wasm spec, only the low 8 bits of the value are used.
827+
828+
```rust
829+
impl<const MAX_PAGES: usize> IsolatedMemory<MAX_PAGES> {
830+
pub fn fill(&mut self, dst: usize, val: u8, len: usize) -> WasmResult<()>;
831+
}
832+
```
833+
834+
Generated code:
835+
```rust
836+
// Wasm: memory.fill $dst $val $len
837+
memory.fill(dst as usize, val as u8, len as usize)?;
838+
```
839+
840+
Traps `OutOfBounds` if `[dst, dst + len)` exceeds active memory. Length zero is a no-op.
841+
842+
#### 4.6.2 `memory.init`
843+
844+
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.
845+
846+
```rust
847+
impl<const MAX_PAGES: usize> IsolatedMemory<MAX_PAGES> {
848+
pub fn init_data_partial(&mut self, dst: usize, data: &[u8], src_offset: usize, len: usize) -> WasmResult<()>;
849+
}
850+
```
851+
852+
Generated code:
853+
```rust
854+
// Wasm: memory.init $data_segment $dst $src_offset $len
855+
memory.init_data_partial(dst as usize, &DATA_SEGMENT_0, src_offset as usize, len as usize)?;
856+
```
857+
858+
Traps `OutOfBounds` if either region (source or destination) exceeds bounds:
859+
- Source: `[src_offset, src_offset + len)` must be within the data segment
860+
- Destination: `[dst, dst + len)` must be within active memory
861+
862+
#### 4.6.3 `data.drop`
863+
864+
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.
865+
866+
```rust
867+
// Wasm: data.drop $segment
868+
// (no-op in safe backend — const slices persist)
869+
```
870+
871+
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.
872+
812873
---
813874

814875
## 5. Integration
@@ -829,7 +890,53 @@ let result = module.process_data(&mut host, ptr, len)?;
829890

830891
Full type safety, zero `unsafe`, zero-cost dispatch via monomorphization.
831892

832-
### 5.2 C-Compatible ABI (Optional)
893+
### 5.2 The Env<H> Context Pattern
894+
895+
> Implementation: [crates/herkos-core/src/codegen/env.rs](../crates/herkos-core/src/codegen/env.rs)
896+
897+
Generated modules use a unified **Env<H>** context struct that bundles the host (generic parameter `H`) and mutable globals, simplifying parameter threading throughout function calls.
898+
899+
```rust
900+
// Generated by transpiler
901+
pub struct Env<'a, H: ModuleHostTrait + ?Sized> {
902+
pub host: &'a mut H,
903+
pub globals: &'a mut Globals,
904+
}
905+
906+
// Every function that needs imports or mutable state receives Env<H>
907+
fn process<H: ModuleHostTrait>(
908+
memory: &mut IsolatedMemory<MAX_PAGES>,
909+
env: &mut Env<H>,
910+
input: i32,
911+
) -> WasmResult<i32> {
912+
// Call imported function via trait
913+
let result = env.host.some_import(input)?;
914+
// Read/write mutable global
915+
env.globals.my_global += 1;
916+
Ok(result)
917+
}
918+
```
919+
920+
**Design rationale:**
921+
- **Unified state**: Avoids threading `host`, `globals`, and other mutable state as separate parameters
922+
- **Type safety**: All imports must be present in the host's trait implementation — checked at compile time
923+
- **Zero overhead**: The Env struct is a thin wrapper; LLVM inlines and optimizes away the indirection
924+
- **Extensibility**: Adding new imports or globals requires only modifying the trait, not all function signatures
925+
926+
**Generated trait:**
927+
928+
```rust
929+
pub trait ModuleHostTrait {
930+
// One method per function import
931+
fn imported_function(&mut self, arg: i32) -> WasmResult<i32>;
932+
933+
// Getter/setter methods for each imported global
934+
fn get_imported_global(&self) -> i32;
935+
fn set_imported_global(&mut self, value: i32);
936+
}
937+
```
938+
939+
### 5.4 C-Compatible ABI (Optional)
833940

834941
For integration with non-Rust systems, an optional `extern "C"` wrapper erases generics:
835942

@@ -849,7 +956,7 @@ pub extern "C" fn module_call(
849956

850957
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.
851958

852-
### 5.3 Native Rust Integration
959+
### 5.5 Native Rust Integration
853960

854961
Native Rust code integrates by implementing import traits directly:
855962

0 commit comments

Comments
 (0)