Skip to content

Commit 9893a51

Browse files
feat: add reusable host imports and simplify function calls
- make host definitions reusable across stores with gc-aware import linking - reorganize function calls, resumable execution, and typed value handling - expand typed tuples to arity 20 and update parser and store APIs Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 8ca9c35 commit 9893a51

41 files changed

Lines changed: 1812 additions & 1403 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Changed
1919

20+
- `HostFunction` is now a reusable definition, and module instantiation borrows `Imports` so host imports can be shared across stores.
21+
- Host function callbacks now require `Send + Sync` so the same definition can be used safely with multiple stores.
22+
- Typed function tuples now support up to 20 parameters or results. `WasmTupleChain` is deprecated. Use untyped functions for larger signatures.
2023
- Module types now use one dense recursive type space, while function types are resolved through `Function::ty(&Store)`.
2124
- Globals are stored in separate 32-bit, 64-bit, and 128-bit value lanes, avoiding tagged value conversion during guest execution.
2225

@@ -27,7 +30,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2730

2831
### Breaking Changes
2932

30-
- Renamed `ModuleInstanceAddr` to `ModuleInstanceId` for consistency.
33+
- `HostFunction::from` and `HostFunction::from_untyped` no longer take a `Store` and now return reusable `HostFunction` definitions
34+
- `ModuleInstance::instantiate` and `instantiate_no_start` now borrow `Imports`.
35+
- `Store::id` now returns `u32` instead of `usize`.
36+
- `Parser::new` now takes `ParserOptions`, use `Parser::default()` for default settings. `Parser::with_options` was removed.
37+
- Renamed `ModuleInstanceAddr` to `ModuleInstanceId`.
3138
- Removed `HostFunction::ty` and `WasmFunction::ty`. Use `Function::ty(&Store)` for runtime function types.
3239
- Changed `TableType::element_type` and `Element::ty` from `WasmType` to `RefType`, and replaced module `table_types` with `TableDefinition { ty, init }`.
3340

‎Cargo.lock‎

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

‎crates/cli/src/wast_runner.rs‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,20 +177,20 @@ impl WastRunner {
177177
.define("spectest", "global_i64", global_i64)
178178
.define("spectest", "global_f32", global_f32)
179179
.define("spectest", "global_f64", global_f64)
180-
.define("spectest", "print", HostFunction::from(store, |_ctx: tinywasm::FuncContext, (): ()| Ok(())))
181-
.define("spectest", "print_i32", HostFunction::from(store, |_ctx: tinywasm::FuncContext, _arg: i32| Ok(())))
182-
.define("spectest", "print_i64", HostFunction::from(store, |_ctx: tinywasm::FuncContext, _arg: i64| Ok(())))
183-
.define("spectest", "print_f32", HostFunction::from(store, |_ctx: tinywasm::FuncContext, _arg: f32| Ok(())))
184-
.define("spectest", "print_f64", HostFunction::from(store, |_ctx: tinywasm::FuncContext, _arg: f64| Ok(())))
180+
.define("spectest", "print", HostFunction::from(|_ctx: tinywasm::FuncContext, (): ()| Ok(())))
181+
.define("spectest", "print_i32", HostFunction::from(|_ctx: tinywasm::FuncContext, _arg: i32| Ok(())))
182+
.define("spectest", "print_i64", HostFunction::from(|_ctx: tinywasm::FuncContext, _arg: i64| Ok(())))
183+
.define("spectest", "print_f32", HostFunction::from(|_ctx: tinywasm::FuncContext, _arg: f32| Ok(())))
184+
.define("spectest", "print_f64", HostFunction::from(|_ctx: tinywasm::FuncContext, _arg: f64| Ok(())))
185185
.define(
186186
"spectest",
187187
"print_i32_f32",
188-
HostFunction::from(store, |_ctx: tinywasm::FuncContext, _args: (i32, f32)| Ok(())),
188+
HostFunction::from(|_ctx: tinywasm::FuncContext, _args: (i32, f32)| Ok(())),
189189
)
190190
.define(
191191
"spectest",
192192
"print_f64_f64",
193-
HostFunction::from(store, |_ctx: tinywasm::FuncContext, _args: (f64, f64)| Ok(())),
193+
HostFunction::from(|_ctx: tinywasm::FuncContext, _args: (f64, f64)| Ok(())),
194194
);
195195

196196
for (name, module) in modules {
@@ -235,7 +235,7 @@ impl WastRunner {
235235
let (name, bytes) = encode_quote_wat(module);
236236
let module = parse_module_bytes(&bytes).expect("failed to parse module bytes");
237237
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
238-
let module_instance = ModuleInstance::instantiate(&mut store, &module, Some(imports))
238+
let module_instance = ModuleInstance::instantiate(&mut store, &module, Some(&imports))
239239
.expect("failed to instantiate module");
240240
(name, module_instance)
241241
})
@@ -331,7 +331,7 @@ impl WastRunner {
331331
let module = parse_module_bytes(&wat.encode().expect("failed to encode module"))
332332
.expect("failed to parse module");
333333
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
334-
ModuleInstance::instantiate(&mut store, &module, Some(imports))?;
334+
ModuleInstance::instantiate(&mut store, &module, Some(&imports))?;
335335
return Ok(());
336336
}
337337
wast::WastExecute::Get { .. } => panic!("get not supported"),
@@ -376,7 +376,7 @@ impl WastRunner {
376376
let module = parse_module_bytes(&module.encode().expect("failed to encode module"))
377377
.expect("failed to parse module");
378378
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
379-
ModuleInstance::instantiate(&mut store, &module, Some(imports))
379+
ModuleInstance::instantiate(&mut store, &module, Some(&imports))
380380
});
381381
match res {
382382
Err(err) => test_group.add_result(

‎crates/parser/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ use tinywasm_parser::{Parser, ParserOptions};
1616

1717
let bytes = include_bytes!("./file.wasm");
1818

19-
let parser = Parser::new();
19+
let parser = Parser::default();
2020
let module = parser.parse_module_bytes(bytes)?;
2121

22-
let parser = Parser::with_options(ParserOptions::default().with_rewrite_optimization(false));
22+
let parser = Parser::new(ParserOptions::default().with_rewrite_optimization(false));
2323
let module = parser.parse_module_bytes(bytes)?;
2424

2525
let module = parser.parse_module_file("path/to/file.wasm")?;
2626
let mut stream = std::fs::File::open("path/to/file.wasm")?;
2727
let module = parser.parse_module_stream(&mut stream)?;
2828
```
2929

30-
If you just want the default configuration, the top-level `parse_bytes`, `parse_file`, and `parse_stream` helpers are thin wrappers around `Parser::new()`.
30+
If you just want the default configuration, the top-level `parse_bytes`, `parse_file`, and `parse_stream` helpers are thin wrappers around `Parser::default()`.

‎crates/parser/src/lib.rs‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ impl Default for ParserOptions {
9090
}
9191

9292
impl ParserOptions {
93+
/// Create parser options with default settings.
94+
pub fn new() -> Self {
95+
Self::default()
96+
}
97+
9398
/// Enable or disable WebAssembly validation.
9499
///
95100
/// Requires the `validate` feature to have any effect.
@@ -152,13 +157,8 @@ pub struct Parser {
152157
}
153158

154159
impl Parser {
155-
/// Create a new parser instance
156-
pub fn new() -> Self {
157-
Self::default()
158-
}
159-
160-
/// Create a new parser with explicit options.
161-
pub fn with_options(options: ParserOptions) -> Self {
160+
/// Create a parser with the given options.
161+
pub const fn new(options: ParserOptions) -> Self {
162162
Self { options }
163163
}
164164

@@ -352,17 +352,17 @@ impl TryFrom<ModuleReader<'_>> for Module {
352352

353353
/// Parse a module from bytes
354354
pub fn parse_bytes(wasm: &[u8]) -> Result<Module> {
355-
Parser::new().parse_module_bytes(wasm)
355+
Parser::default().parse_module_bytes(wasm)
356356
}
357357

358358
#[cfg(feature = "std")]
359359
/// Parse a module from a file. Requires the `std` feature.
360360
pub fn parse_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Module> {
361-
Parser::new().parse_module_file(path)
361+
Parser::default().parse_module_file(path)
362362
}
363363

364364
#[cfg(feature = "std")]
365365
/// Parse a module from a stream. Requires the `std` feature.
366366
pub fn parse_stream(stream: impl crate::std::io::Read) -> Result<Module> {
367-
Parser::new().parse_module_stream(stream)
367+
Parser::default().parse_module_stream(stream)
368368
}

‎crates/tinywasm/benches/argon2id.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use types::Module;
66
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.wasm");
77

88
fn argon2id_parse() -> Result<Module> {
9-
let parser = tinywasm_parser::Parser::new();
9+
let parser = tinywasm_parser::Parser::default();
1010
let data = parser.parse_module_bytes(WASM)?;
1111
Ok(data)
1212
}

‎crates/tinywasm/benches/fibonacci.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use types::Module;
66
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.wasm");
77

88
fn fibonacci_parse() -> Result<Module> {
9-
let parser = tinywasm_parser::Parser::new();
9+
let parser = tinywasm_parser::Parser::default();
1010
let data = parser.parse_module_bytes(WASM)?;
1111
Ok(data)
1212
}

‎crates/tinywasm/benches/tinywasm.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use criterion::{Criterion, criterion_group, criterion_main};
22
use eyre::Result;
33
use tinywasm::engine::Config;
4-
use tinywasm::{Engine, FuncContext, HostFunction, Imports, MemoryBackend, ModuleInstance, Store, types};
4+
use tinywasm::{Engine, FuncContext, HostFunction, Imports, ModuleInstance, Store, types};
55
use types::Module;
66

77
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.wasm");
88

99
fn tinywasm_parse() -> Result<Module> {
10-
let parser = tinywasm_parser::Parser::new();
10+
let parser = tinywasm_parser::Parser::default();
1111
let data = parser.parse_module_bytes(WASM)?;
1212
Ok(data)
1313
}
@@ -26,8 +26,8 @@ fn tinywasm_run(module: &Module) -> Result<()> {
2626
let engine = Engine::new(Config::default());
2727
let mut store = Store::new(engine);
2828
let mut imports = Imports::default();
29-
imports.define("env", "printi32", HostFunction::from(&mut store, |_: FuncContext<'_>, _: i32| Ok(())));
30-
let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
29+
imports.define("env", "printi32", HostFunction::from(|_: FuncContext<'_>, _: i32| Ok(())));
30+
let instance = ModuleInstance::instantiate(&mut store, module, Some(&imports)).expect("instantiate");
3131
let hello = instance.func::<(), ()>(&store, "hello").expect("func_typed");
3232
hello.call(&mut store, ()).expect("call");
3333
Ok(())

‎crates/tinywasm/benches/tinywasm_modes.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const TIME_BUDGET_PER_ROUND: core::time::Duration = core::time::Duration::from_m
1010
const BENCH_MEASUREMENT_TIME: core::time::Duration = core::time::Duration::from_secs(10);
1111

1212
fn tinywasm_parse() -> Result<Module> {
13-
let parser = tinywasm_parser::Parser::new();
13+
let parser = tinywasm_parser::Parser::default();
1414
Ok(parser.parse_module_bytes(WASM)?)
1515
}
1616

@@ -21,9 +21,9 @@ fn setup_typed_func(module: &Module, engine: Option<Engine>) -> Result<(Store, F
2121
};
2222

2323
let mut imports = Imports::default();
24-
imports.define("env", "printi32", HostFunction::from(&mut store, |_: FuncContext<'_>, _: i32| Ok(())));
24+
imports.define("env", "printi32", HostFunction::from(|_: FuncContext<'_>, _: i32| Ok(())));
2525

26-
let instance = ModuleInstance::instantiate(&mut store, module, Some(imports))?;
26+
let instance = ModuleInstance::instantiate(&mut store, module, Some(&imports))?;
2727
let func = instance.func::<(), ()>(&store, "hello")?;
2828
Ok((store, func))
2929
}

0 commit comments

Comments
 (0)