Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d8d439e

Browse files
feat: add more examples, work on new public api
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 67f0fd6 commit d8d439e

File tree

23 files changed

+138
-45
lines changed

23 files changed

+138
-45
lines changed

.cargo/config.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[alias]
22
version-dev="workspaces version --no-git-commit --force tinywasm*"
33
dev="run -- -l debug run"
4-
54
test-mvp="test --package tinywasm --test test-mvp --release -- --enable "
65
test-2="test --package tinywasm --test test-two --release -- --enable "
76
test-wast="test --package tinywasm --test test-wast -- --enable "

.github/workflows/test.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ jobs:
2020
run: rustup update stable
2121

2222
- name: Build (stable)
23-
run: cargo +stable build --workspace --exclude wasm-testsuite
23+
run: cargo +stable build --workspace
2424

2525
- name: Run tests (stable)
26-
run: cargo +stable test --workspace --exclude wasm-testsuite
26+
run: cargo +stable test --workspace
2727

2828
- name: Run MVP testsuite
2929
run: cargo +stable test-mvp
@@ -41,10 +41,10 @@ jobs:
4141
run: rustup update nightly
4242

4343
- name: Build (nightly, no default features)
44-
run: cargo +nightly build --workspace --exclude wasm-testsuite --exclude rust-wasm-examples --no-default-features
44+
run: cargo +nightly build --workspace --no-default-features
4545

4646
- name: Run tests (nightly, no default features)
47-
run: cargo +nightly test --workspace --exclude wasm-testsuite --exclude rust-wasm-examples --no-default-features
47+
run: cargo +nightly test --workspace --no-default-features
4848

4949
- name: Run MVP testsuite (nightly)
5050
run: cargo +nightly test-mvp

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/target
22
notes.md
33
examples/rust/out/*
4+
examples/rust/target
5+
examples/rust/Cargo.lock
46
examples/wast/*

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"search.exclude": {
33
"**/wasm-testsuite/data": true
4-
}
4+
},
5+
"rust-analyzer.linkedProjects": [
6+
"./Cargo.toml",
7+
"./examples/rust/Cargo.toml"
8+
]
59
}

Cargo.lock

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

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members=["crates/*", "examples/rust"]
2+
members=["crates/*"]
33
resolver="2"
44

55
[profile.wasm]
@@ -21,6 +21,10 @@ name="tinywasm-root"
2121
publish=false
2222
edition="2021"
2323

24+
[[example]]
25+
name="wasm-rust"
26+
test=false
27+
2428
[dev-dependencies]
2529
color-eyre="0.6"
2630
tinywasm={path="crates/tinywasm"}

crates/cli/src/bin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ fn run(module: Module, func: Option<String>, args: Vec<WasmValue>) -> Result<()>
112112
let instance = module.instantiate(&mut store, None)?;
113113

114114
if let Some(func) = func {
115-
let func = instance.exported_func_by_name(&store, &func)?;
115+
let func = instance.exported_func_untyped(&store, &func)?;
116116
let res = func.call(&mut store, &args)?;
117117
info!("{res:?}");
118118
}

crates/tinywasm/src/export.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

crates/tinywasm/src/imports.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ impl FuncContext<'_> {
7777
pub fn module(&self) -> &crate::ModuleInstance {
7878
self.module
7979
}
80+
81+
/// Get a reference to an exported memory
82+
pub fn memory(&mut self, name: &str) -> Result<crate::MemoryRef> {
83+
self.module.exported_memory(self.store, name)
84+
}
8085
}
8186

8287
impl Debug for HostFunction {
@@ -276,7 +281,7 @@ impl Imports {
276281

277282
if let Some(addr) = self.modules.get(&name.module) {
278283
let instance = store.get_module_instance(*addr)?;
279-
return Some(ResolvedExtern::Store(instance.export(&import.name)?));
284+
return Some(ResolvedExtern::Store(instance.export_addr(&import.name)?));
280285
}
281286

282287
None
@@ -398,7 +403,7 @@ impl Imports {
398403
Self::compare_table_types(import, &table.borrow().kind, ty)?;
399404
imports.tables.push(table_addr);
400405
}
401-
(ExternVal::Mem(memory_addr), ImportKind::Memory(ty)) => {
406+
(ExternVal::Memory(memory_addr), ImportKind::Memory(ty)) => {
402407
let mem = store.get_mem(memory_addr as usize)?;
403408
let (size, kind) = {
404409
let mem = mem.borrow();

crates/tinywasm/src/instance.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use alloc::{boxed::Box, format, string::ToString, sync::Arc};
2-
use tinywasm_types::{
3-
DataAddr, ElemAddr, Export, ExternVal, ExternalKind, FuncAddr, FuncType, GlobalAddr, Import, MemAddr,
4-
ModuleInstanceAddr, TableAddr,
5-
};
2+
use tinywasm_types::*;
63

74
use crate::{
85
func::{FromWasmValueTuple, IntoWasmValueTuple},
9-
log, Error, FuncHandle, FuncHandleTyped, Imports, Module, Result, Store,
6+
log, Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, Module, Result, Store,
107
};
118

129
/// An instanciated WebAssembly module
@@ -106,7 +103,7 @@ impl ModuleInstance {
106103
}
107104

108105
/// Get a export by name
109-
pub fn export(&self, name: &str) -> Option<ExternVal> {
106+
pub fn export_addr(&self, name: &str) -> Option<ExternVal> {
110107
let exports = self.0.exports.iter().find(|e| e.name == name.into())?;
111108
let kind = exports.kind.clone();
112109
let addr = match kind {
@@ -162,12 +159,12 @@ impl ModuleInstance {
162159
}
163160

164161
/// Get an exported function by name
165-
pub fn exported_func_by_name(&self, store: &Store, name: &str) -> Result<FuncHandle> {
162+
pub fn exported_func_untyped(&self, store: &Store, name: &str) -> Result<FuncHandle> {
166163
if self.0.store_id != store.id() {
167164
return Err(Error::InvalidStore);
168165
}
169166

170-
let export = self.export(name).ok_or_else(|| Error::Other(format!("Export not found: {}", name)))?;
167+
let export = self.export_addr(name).ok_or_else(|| Error::Other(format!("Export not found: {}", name)))?;
171168
let ExternVal::Func(func_addr) = export else {
172169
return Err(Error::Other(format!("Export is not a function: {}", name)));
173170
};
@@ -179,15 +176,32 @@ impl ModuleInstance {
179176
}
180177

181178
/// Get a typed exported function by name
182-
pub fn typed_func<P, R>(&self, store: &Store, name: &str) -> Result<FuncHandleTyped<P, R>>
179+
pub fn exported_func<P, R>(&self, store: &Store, name: &str) -> Result<FuncHandleTyped<P, R>>
183180
where
184181
P: IntoWasmValueTuple,
185182
R: FromWasmValueTuple,
186183
{
187-
let func = self.exported_func_by_name(store, name)?;
184+
let func = self.exported_func_untyped(store, name)?;
188185
Ok(FuncHandleTyped { func, marker: core::marker::PhantomData })
189186
}
190187

188+
/// Get an exported memory by name
189+
pub fn exported_memory(&self, store: &mut Store, name: &str) -> Result<MemoryRef> {
190+
let export = self.export_addr(name).ok_or_else(|| Error::Other(format!("Export not found: {}", name)))?;
191+
let ExternVal::Memory(mem_addr) = export else {
192+
return Err(Error::Other(format!("Export is not a memory: {}", name)));
193+
};
194+
let mem = self.memory(store, mem_addr)?;
195+
Ok(mem)
196+
}
197+
198+
/// Get a memory by address
199+
pub fn memory(&self, store: &Store, addr: MemAddr) -> Result<MemoryRef> {
200+
let addr = self.resolve_mem_addr(addr);
201+
let mem = store.get_mem(addr as usize)?;
202+
Ok(MemoryRef { instance: mem.clone() })
203+
}
204+
191205
/// Get the start function of the module
192206
///
193207
/// Returns None if the module has no start function
@@ -204,7 +218,7 @@ impl ModuleInstance {
204218
Some(func_index) => func_index,
205219
None => {
206220
// alternatively, check for a _start function in the exports
207-
let Some(ExternVal::Func(func_addr)) = self.export("_start") else {
221+
let Some(ExternVal::Func(func_addr)) = self.export_addr("_start") else {
208222
return Ok(None);
209223
};
210224

crates/tinywasm/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
//! // Get a typed handle to the exported "add" function
5252
//! // Alternatively, you can use `instance.get_func` to get an untyped handle
5353
//! // that takes and returns [`WasmValue`]s
54-
//! let func = instance.typed_func::<(i32, i32), i32>(&mut store, "add")?;
54+
//! let func = instance.exported_func::<(i32, i32), i32>(&mut store, "add")?;
5555
//! let res = func.call(&mut store, (1, 2))?;
5656
//!
5757
//! assert_eq!(res, 3);
@@ -99,6 +99,9 @@ pub use module::Module;
9999
mod instance;
100100
pub use instance::ModuleInstance;
101101

102+
mod reference;
103+
pub use reference::*;
104+
102105
mod func;
103106
pub use func::{FuncHandle, FuncHandleTyped};
104107

crates/tinywasm/src/reference.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use core::cell::RefCell;
2+
3+
use alloc::rc::Rc;
4+
5+
use crate::{GlobalInstance, MemoryInstance};
6+
7+
/// A reference to a memory instance
8+
#[derive(Debug, Clone)]
9+
pub struct MemoryRef {
10+
pub(crate) instance: Rc<RefCell<MemoryInstance>>,
11+
}
12+
13+
/// A reference to a global instance
14+
#[derive(Debug, Clone)]
15+
pub struct GlobalRef {
16+
pub(crate) instance: Rc<RefCell<GlobalInstance>>,
17+
}

crates/tinywasm/tests/testsuite/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ impl TestSuite {
428428
continue;
429429
};
430430

431-
let module_global = match match module.export(global) {
431+
let module_global = match match module.export_addr(global) {
432432
Some(ExternVal::Global(addr)) => {
433433
store.get_global_val(addr as usize).map_err(|_| eyre!("failed to get global"))
434434
}

crates/tinywasm/tests/testsuite/util.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn exec_fn_instance(
2525
return Err(tinywasm::Error::Other("no instance found".to_string()));
2626
};
2727

28-
let func = instance.exported_func_by_name(store, name)?;
28+
let func = instance.exported_func_untyped(store, name)?;
2929
func.call(store, args)
3030
}
3131

@@ -42,7 +42,7 @@ pub fn exec_fn(
4242
let mut store = tinywasm::Store::new();
4343
let module = tinywasm::Module::from(module);
4444
let instance = module.instantiate(&mut store, imports)?;
45-
instance.exported_func_by_name(&store, name)?.call(&mut store, args)
45+
instance.exported_func_untyped(&store, name)?.call(&mut store, args)
4646
}
4747

4848
pub fn catch_unwind_silent<F: FnOnce() -> R, R>(f: F) -> std::thread::Result<R> {

crates/types/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ pub type ModuleInstanceAddr = Addr;
316316
pub enum ExternVal {
317317
Func(FuncAddr),
318318
Table(TableAddr),
319-
Mem(MemAddr),
319+
Memory(MemAddr),
320320
Global(GlobalAddr),
321321
}
322322

@@ -325,7 +325,7 @@ impl ExternVal {
325325
match self {
326326
Self::Func(_) => ExternalKind::Func,
327327
Self::Table(_) => ExternalKind::Table,
328-
Self::Mem(_) => ExternalKind::Memory,
328+
Self::Memory(_) => ExternalKind::Memory,
329329
Self::Global(_) => ExternalKind::Global,
330330
}
331331
}
@@ -334,7 +334,7 @@ impl ExternVal {
334334
match kind {
335335
ExternalKind::Func => Self::Func(addr),
336336
ExternalKind::Table => Self::Table(addr),
337-
ExternalKind::Memory => Self::Mem(addr),
337+
ExternalKind::Memory => Self::Memory(addr),
338338
ExternalKind::Global => Self::Global(addr),
339339
}
340340
}

examples/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Examples
22

3-
## WasmRust
3+
## Wasm-Rust
44

55
These are examples using WebAssembly generated from Rust code.
6-
To run these, you first need to build the Rust code into WebAssembly, since the wasm files are not included in the repository to keep it small.
7-
This requires the `wasm32-unknown-unknown` target and `wasm-opt` to be installed (available via Binaryen).
6+
To run these, you first need to build the Rust code, since the resulting wasm files are not included in the repository to keep it small.
7+
This requires the `wasm32-unknown-unknown` target and `wasm-opt` to be installed (available via [Binaryen](https://github.com/WebAssembly/binaryen)).
88

99
```bash
1010
$ ./examples/rust/build.sh
@@ -20,3 +20,4 @@ Where `<example>` is one of the following:
2020

2121
- `hello`: A simple example that prints a number to the console.
2222
- `tinywasm`: Runs `hello` using TinyWasm - inside of TinyWasm itself!
23+
- `fibonacci`: Calculates the x-th Fibonacci number.

examples/rust/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
cargo-features=["per-package-target"]
22

3+
# treat this as an independent package
4+
[workspace]
5+
36
[package]
47
publish=false
58
name="rust-wasm-examples"
@@ -16,3 +19,14 @@ path="src/hello.rs"
1619
[[bin]]
1720
name="tinywasm"
1821
path="src/tinywasm.rs"
22+
23+
[[bin]]
24+
name="fibonacci"
25+
path="src/fibonacci.rs"
26+
27+
[profile.wasm]
28+
opt-level="s"
29+
lto="thin"
30+
codegen-units=1
31+
panic="abort"
32+
inherits="release"

examples/rust/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
# Examples using Rust compiled to WebAssembly
1+
# WebAssembly Rust Examples
2+
3+
This is a seperate crate that generates WebAssembly from Rust code.
4+
It is used by the `wasm-rust` example.

examples/rust/build.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#!/usr/bin/env bash
22
cd "$(dirname "$0")"
33

4-
bins=("hello" "tinywasm")
4+
bins=("hello" "tinywasm" "fibonacci")
55
exclude_wat=("tinywasm")
6-
out_dir="../../target/wasm32-unknown-unknown/wasm"
6+
out_dir="./target/wasm32-unknown-unknown/wasm"
77
dest_dir="out"
88

9+
# ensure out dir exists
10+
mkdir -p "$dest_dir"
11+
912
for bin in "${bins[@]}"; do
1013
cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin"
1114

examples/rust/src/fibonacci.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
#[cfg(not(test))]
5+
#[panic_handler]
6+
fn panic(_info: &core::panic::PanicInfo) -> ! {
7+
core::arch::wasm32::unreachable()
8+
}
9+
10+
#[no_mangle]
11+
// The rust compiler will convert this to an iterative algorithm.
12+
pub extern "C" fn fibonacci(n: i32) -> i32 {
13+
if n <= 1 {
14+
return n;
15+
}
16+
fibonacci(n - 1) + fibonacci(n - 2)
17+
}

examples/rust/src/tinywasm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn run() -> tinywasm::Result<()> {
2626
)?;
2727
let instance = module.instantiate(&mut store, Some(imports))?;
2828

29-
let add_and_print = instance.typed_func::<(i32, i32), ()>(&mut store, "add_and_print")?;
29+
let add_and_print = instance.exported_func::<(i32, i32), ()>(&mut store, "add_and_print")?;
3030
add_and_print.call(&mut store, (1, 2))?;
3131
Ok(())
3232
}

0 commit comments

Comments
 (0)