Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added support for the WebAssembly function-references proposal
- Added support for the WebAssembly garbage-collection proposal
- Added `WasmValue::ty` and `WasmValue::matches_type`
- Added a `validate` feature to `tinywasm` and `tinywasm-parser` (enabled by default) to optionally skip wasmparser validation for faster parsing of trusted modules.

### Changed

- Function types are now stored separately and resolved through `Function::ty(&Store)`.
- Module types now use one dense recursive type space, while function types are resolved through `Function::ty(&Store)`.

### Fixed

Expand Down
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ categories = ["compilers", "embedded", "no-std", "virtualization", "wasm"]

[workspace.dependencies]
tinywasm = { path = "crates/tinywasm", version = "0.11.0-pre.0", default-features = false }
tinywasm-cli = { path = "crates/cli", version = "0.11.0-pre.0", default-features = false }
tinywasm-parser = { path = "crates/parser", version = "0.11.0-pre.0", default-features = false }
tinywasm-types = { path = "crates/types", version = "0.11.0-pre.0", default-features = false }

eyre = "0.6"
indexmap = "2.14"
log = "0.4"
owo-colors = { version = "4.3" }
pretty_env_logger = "0.5"
Expand Down
48 changes: 26 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ See the [examples](./examples) directory and [documentation](https://docs.rs/tin

With default features disabled, `tinywasm` depends only on `core`, `alloc`, and `libm`[^libm], making it usable in `no_std + alloc` environments.

Use `Engine` and `engine::Config` when you need non-default runtime settings such as fuel accounting, stack sizing, memory backend selection, or trap-on-OOM behavior.
Use `Engine` and `engine::Config` when you need non-default runtime settings such as fuel accounting, stack sizing, memory backend selection, the GC collection threshold, or trap-on-OOM behavior.

[^libm]: [rust-lang/rust#137578](https://github.com/rust-lang/rust/issues/137578) — tracking issue for floating-point math support in `no_std`.

Expand All @@ -75,27 +75,31 @@ The internal `twasm` bytecode format is not currently validated as an untrusted

## Supported Proposals

| Proposal | Status | `tinywasm` Version |
| --------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------------ |
| [**Multi-value**](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md) | 🟢 | 0.2.0 |
| [**Mutable Globals**](https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md) | 🟢 | 0.2.0 |
| [**Non-trapping float-to-int Conversion**](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) | 🟢 | 0.2.0 |
| [**Sign-extension operators**](https://github.com/WebAssembly/sign-extension-ops) | 🟢 | 0.2.0 |
| [**Bulk Memory Operations**](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md) | 🟢 | 0.4.0 |
| [**Reference Types**](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) | 🟢 | 0.7.0 |
| [**Multi-memory**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) | 🟢 | 0.8.0 |
| [**Custom Page Sizes**](https://github.com/WebAssembly/custom-page-sizes/blob/main/proposals/custom-page-sizes/Overview.md) | 🟢 | 0.9.0 |
| [**Extended Const**](https://github.com/WebAssembly/extended-const/blob/main/proposals/extended-const/Overview.md) | 🟢 | 0.9.0 |
| [**Fixed-Width SIMD**](https://github.com/WebAssembly/simd/blob/main/proposals/simd/Overview.md) | 🟢 | 0.9.0 |
| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🟢 | 0.9.0 |
| [**Tail Call**](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md) | 🟢 | 0.9.0 |
| [**Relaxed SIMD**](https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md) | 🟢 | 0.9.0 |
| [**Wide Arithmetic**](https://github.com/WebAssembly/wide-arithmetic/blob/main/proposals/wide-arithmetic/Overview.md) | 🟢 | 0.9.0 |
| [**Typed Function References**](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md) | 🚧 | `next` |
| [**Exception Handling**](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md) | 🌑 | - |
| [**Garbage Collection**](https://github.com/WebAssembly/gc/blob/main/proposals/gc/Overview.md) | 🌑 | - |
| [**Stack Switching**](https://github.com/WebAssembly/stack-switching/blob/main/proposals/stack-switching/Explainer.md) | 🌑 | - |
| [**Threads**](https://github.com/WebAssembly/threads/blob/main-legacy/proposals/threads/Overview.md) | 🌑 | - |
TinyWasm targets non-JavaScript core proposals through [phase 3](https://github.com/WebAssembly/proposals). JavaScript integrations and optional embedding or tooling APIs are not included here.

| Proposal | Status | `tinywasm` Version |
| ---------------------------------------------------------------------------------------------------------------- | ------ | ------------------ |
| [**Import/Export of Mutable Globals**](https://github.com/WebAssembly/mutable-global) | 🟢 | 0.2.0 |
| [**Multi-value**](https://github.com/WebAssembly/multi-value) | 🟢 | 0.2.0 |
| [**Non-trapping Float-to-int Conversions**](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) | 🟢 | 0.2.0 |
| [**Sign-extension Operators**](https://github.com/WebAssembly/sign-extension-ops) | 🟢 | 0.2.0 |
| [**Bulk Memory Operations**](https://github.com/WebAssembly/bulk-memory-operations) | 🟢 | 0.4.0 |
| [**Reference Types**](https://github.com/WebAssembly/reference-types) | 🟢 | 0.7.0 |
| [**Fixed-width SIMD**](https://github.com/WebAssembly/simd) | 🟢 | 0.9.0 |
| [**Tail Calls**](https://github.com/WebAssembly/tail-call) | 🟢 | 0.9.0 |
| [**Extended Constant Expressions**](https://github.com/WebAssembly/extended-const) | 🟢 | 0.9.0 |
| [**Multiple Memories**](https://github.com/WebAssembly/multi-memory) | 🟢 | 0.8.0 |
| [**Relaxed SIMD**](https://github.com/WebAssembly/relaxed-simd) | 🟢 | 0.9.0 |
| [**Custom Annotation Syntax**](https://github.com/WebAssembly/annotations) | 🟢 | 0.8.0 |
| [**Memory64**](https://github.com/WebAssembly/memory64) | 🟢 | 0.9.0 |
| [**Wide Arithmetic**](https://github.com/WebAssembly/wide-arithmetic) | 🟢 | 0.9.0 |
| [**Custom Page Sizes**](https://github.com/WebAssembly/custom-page-sizes) | 🟢 | 0.9.0 |
| [**Typed Function References**](https://github.com/WebAssembly/function-references) | 🟢 | `next` |
| [**Garbage Collection**](https://github.com/WebAssembly/gc) | 🟢 | `next` |
| [**Exception Handling**](https://github.com/WebAssembly/exception-handling) | 🌑 | - |
| [**Stack Switching**](https://github.com/WebAssembly/stack-switching) | 🌑 | - |
| [**Compact Import Section**](https://github.com/WebAssembly/compact-import-section) | 🌑 | - |
| [**Threads**](https://github.com/WebAssembly/threads) | 🌑 | - |

**Legend**\
🌑 -- not available\
Expand Down
55 changes: 45 additions & 10 deletions crates/cli/src/wast_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use std::time::Duration;

use eyre::{Context, Result, bail, eyre};
use log::{debug, error};
use tinywasm::types::{ExternRef, FuncRef, MemoryType, RefType, RefValue, TableType, WasmType, WasmValue};
use tinywasm::types::{
AbstractHeapType as TinyAbstractHeapType, AnyRef, ExternRef, FuncRef, MemoryType, RefType, RefValue, TableType,
WasmType, WasmValue,
};
use tinywasm::{ExecProgress, Global, HostFunction, Imports, Memory, Module, ModuleInstance, Store, Table};
use wast::{QuoteWat, core::AbstractHeapType};

Expand Down Expand Up @@ -459,7 +462,7 @@ impl WastRunner {
let expected = expected_alternatives
.iter()
.filter_map(|alts| alts.first())
.find(|exp| exp.matches(&module_global));
.find(|exp| exp.matches(&module_global, &store));
if expected.is_none() {
test_group.add_result(
&format!("AssertReturn(unsupported-{i})"),
Expand Down Expand Up @@ -508,7 +511,10 @@ impl WastRunner {
}
if expected_alternatives.iter().any(|expected| {
expected.len() == outcomes.len()
&& outcomes.iter().zip(expected.iter()).all(|(outcome, exp)| exp.matches(outcome))
&& outcomes
.iter()
.zip(expected.iter())
.all(|(outcome, exp)| exp.matches(outcome, &store))
}) {
Ok(())
} else {
Expand Down Expand Up @@ -755,16 +761,18 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result<WasmValue> {
I32(i) => WasmValue::I32(i),
I64(i) => WasmValue::I64(i),
V128(i) => WasmValue::V128(i.to_le_bytes()),
RefExtern(v) => ExternRef::new(v).into(),
RefExtern(v) => ExternRef::try_new(v).ok_or_else(|| eyre!("external reference address is too large"))?.into(),
RefNull(t) => match t {
wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Func } => RefValue::Null.into(),
wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Extern } => RefValue::Null.into(),
wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Extern | AbstractHeapType::Any } => {
RefValue::Null.into()
}
_ => {
bail!("unsupported arg type: refnull: {:?}", t);
}
},
RefHost(_) => {
bail!("unsupported arg type: RefHost");
RefHost(value) => {
RefValue::Any(AnyRef::from_host(value).ok_or_else(|| eyre!("host reference address is too large"))?).into()
}
})
}
Expand All @@ -791,15 +799,29 @@ enum ExpectedValue {
RefNull,
RefFunc,
RefExtern,
RefAny,
RefEq,
RefI31,
RefStruct,
RefArray,
}

impl ExpectedValue {
fn matches(&self, value: &WasmValue) -> bool {
fn matches(&self, value: &WasmValue, store: &Store) -> bool {
match self {
Self::Exact(expected) => value.eq_loose(expected),
Self::RefNull => matches!(value, WasmValue::Ref(RefValue::Null)),
Self::RefFunc => matches!(value, WasmValue::Ref(RefValue::Func(_))),
Self::RefExtern => matches!(value, WasmValue::Ref(RefValue::Extern(_))),
Self::RefAny => matches!(value, WasmValue::Ref(RefValue::Any(_))),
Self::RefEq => {
store.value_matches_type(*value, WasmType::Ref(RefType::new_abstract(false, TinyAbstractHeapType::Eq)))
}
Self::RefI31 => matches!(value, WasmValue::Ref(RefValue::Any(value)) if value.as_i31().is_some()),
Self::RefStruct => store
.value_matches_type(*value, WasmType::Ref(RefType::new_abstract(false, TinyAbstractHeapType::Struct))),
Self::RefArray => store
.value_matches_type(*value, WasmType::Ref(RefType::new_abstract(false, TinyAbstractHeapType::Array))),
}
}
}
Expand All @@ -817,21 +839,34 @@ fn wastret2tinywasmvalues(ret: wast::WastRet) -> Result<Vec<ExpectedValue>> {
}

fn wastretcore2tinywasmvalue(ret: wast::core::WastRetCore) -> Result<ExpectedValue> {
use wast::core::WastRetCore::{F32, F64, I32, I64, RefExtern, RefFunc, RefNull, V128};
use wast::core::WastRetCore::{
F32, F64, I32, I64, RefAny, RefArray, RefEq, RefExtern, RefFunc, RefHost, RefI31, RefI31Shared, RefNull,
RefStruct, V128,
};
Ok(match ret {
F32(f) => ExpectedValue::Exact(nanpattern2tinywasmvalue(f)?),
F64(f) => ExpectedValue::Exact(nanpattern2tinywasmvalue(f)?),
I32(i) => ExpectedValue::Exact(WasmValue::I32(i)),
I64(i) => ExpectedValue::Exact(WasmValue::I64(i)),
V128(i) => ExpectedValue::Exact(WasmValue::V128(wast_v128_to_bytes(i))),
RefNull(_) => ExpectedValue::RefNull,
RefExtern(Some(v)) => ExpectedValue::Exact(ExternRef::new(v).into()),
RefExtern(Some(v)) => ExpectedValue::Exact(
ExternRef::try_new(v).ok_or_else(|| eyre!("external reference address is too large"))?.into(),
),
RefExtern(None) => ExpectedValue::RefExtern,
RefFunc(Some(wast::token::Index::Num(n, _))) => ExpectedValue::Exact(FuncRef::new(n).into()),
RefFunc(None) => ExpectedValue::RefFunc,
RefFunc(v) => {
bail!("unsupported arg type: reffunc: {:?}", v);
}
RefAny => ExpectedValue::RefAny,
RefEq => ExpectedValue::RefEq,
RefI31 | RefI31Shared => ExpectedValue::RefI31,
RefStruct => ExpectedValue::RefStruct,
RefArray => ExpectedValue::RefArray,
RefHost(value) => ExpectedValue::Exact(
RefValue::Any(AnyRef::from_host(value).ok_or_else(|| eyre!("host reference address is too large"))?).into(),
),
a => {
bail!("unsupported arg type {:?}", a);
}
Expand Down
Loading
Loading