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

Skip to content

Commit 963ddd2

Browse files
chore: add more examples, refactoring
Signed-off-by: Henry Gressmann <[email protected]>
1 parent f865161 commit 963ddd2

File tree

22 files changed

+378
-307
lines changed

22 files changed

+378
-307
lines changed

Cargo.lock

Lines changed: 1 addition & 0 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
@@ -44,6 +44,7 @@ color-eyre="0.6"
4444
criterion={version="0.5", features=["html_reports"]}
4545

4646
tinywasm={path="crates/tinywasm"}
47+
wat={version="1.0"}
4748
wasmi={version="0.31", features=["std"]}
4849
wasmer={version="4.2", features=["cranelift", "singlepass"]}
4950
wasmtime={version="17.0", features=["cranelift"]}

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@
1010

1111
[![docs.rs](https://img.shields.io/docsrs/tinywasm?logo=rust)](https://docs.rs/tinywasm) [![Crates.io](https://img.shields.io/crates/v/tinywasm.svg?logo=rust)](https://crates.io/crates/tinywasm) [![Crates.io](https://img.shields.io/crates/l/tinywasm.svg)](./LICENSE-APACHE)
1212

13-
# Why TinyWasm?
13+
## Why TinyWasm?
1414

1515
- **Tiny** - Designed to be as small as possible without sacrificing too much performance or functionality.
1616
- **Fast enough** - TinyWasm is reasonably fast, especially when compared to other interpreters. See [Performance](#performance) for more details.
1717
- **Portable** - Runs on any platform llvm supports, including WebAssembly. Minimal external dependencies.
1818

19-
# Status
19+
## Status
2020

21-
TinyWasm, starting from version `0.3.0`, passes all the WebAssembly 1.0 tests in the [WebAssembly Test Suite](https://github.com/WebAssembly/testsuite). The 2.0 tests are in progress. This is enough to run most WebAssembly programs, including TinyWasm itself compiled to WebAssembly (see [examples/wasm-rust.rs](./examples/wasm-rust.rs)).
21+
TinyWasm, starting from version `0.3.0`, passes all the WebAssembly 1.0 tests in the [WebAssembly Test Suite](https://github.com/WebAssembly/testsuite). The 2.0 tests are in progress. This is enough to run most WebAssembly programs, including TinyWasm itself compiled to WebAssembly (see [examples/wasm-rust.rs](./examples/wasm-rust.rs)). Results of the testsuite can be found [here](https://github.com/explodingcamera/tinywasm/tree/main/crates/tinywasm/tests/generated).
2222

2323
Some APIs to interact with the runtime are not yet exposed, and the existing ones are subject to change, but the core functionality is mostly complete.
24-
Results of the tests can be found [here](https://github.com/explodingcamera/tinywasm/tree/main/crates/tinywasm/tests/generated).
2524

2625
TinyWasm is not designed for performance, but rather for simplicity, size and portability. However, it is still reasonably fast, especially when compared to other interpreters. See [Performance](#performance) for more details.
2726

@@ -32,24 +31,26 @@ TinyWasm is not designed for performance, but rather for simplicity, size and po
3231
- [**Sign-extension operators**](https://github.com/WebAssembly/spec/blob/master/proposals/sign-extension-ops/Overview.md) - **Fully implemented**
3332
- [**Bulk Memory Operations**](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md) - **Fully implemented** (as of version `0.4.0`)
3433
- [**Reference Types**](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) - **_Partially implemented_**
35-
- [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) - **_Partially implemented_** (not tested yet)
36-
- [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) - **_Partially implemented_** (only 32-bit addressing is supported at the moment, but larger memories can be created)
34+
- [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) - **_Partially implemented_**
35+
- [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) - **_Partially implemented_**
3736

3837
## Usage
3938

4039
TinyWasm can be used through the `tinywasm-cli` CLI tool or as a library in your Rust project. Documentation can be found [here](https://docs.rs/tinywasm).
4140

42-
### CLI
41+
### Library
4342

4443
```sh
45-
$ cargo install tinywasm-cli
46-
$ tinywasm-cli --help
44+
$ cargo add tinywasm
4745
```
4846

49-
### Library
47+
### CLI
48+
49+
The CLI is mainly available for testing purposes, but can also be used to run WebAssembly programs.
5050

5151
```sh
52-
$ cargo add tinywasm
52+
$ cargo install tinywasm-cli
53+
$ tinywasm-cli --help
5354
```
5455

5556
## Feature Flags
@@ -60,6 +61,8 @@ $ cargo add tinywasm
6061
Enables logging using the `log` crate. This is enabled by default.
6162
- **`parser`**\
6263
Enables the `tinywasm-parser` crate. This is enabled by default.
64+
- **`archive`**\
65+
Enables pre-parsing of archives. This is enabled by default.
6366
- **`unsafe`**\
6467
Uses `unsafe` code to improve performance, particularly in Memory access
6568

@@ -70,7 +73,7 @@ Since `libm` is not as performant as the compiler's math intrinsics, it is recom
7073

7174
> Benchmarks are coming soon.
7275
73-
# 📄 License
76+
## License
7477

7578
Licensed under either of [Apache License, Version 2.0](./LICENSE-APACHE) or [MIT license](./LICENSE-MIT) at your option.
7679

crates/cli/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# `tinywasm-cli`
2+
3+
The `tinywasm-cli` crate contains the command line interface for the `tinywasm` project. See [`tinywasm`](https://crates.io/crates/tinywasm) for more information.
4+
5+
## Usage
6+
7+
```bash
8+
$ cargo install tinywasm-cli
9+
$ tinywasm-cli --help
10+
```

crates/parser/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# `tinywasm-parser`
22

3-
This crate provides a parser that can parse WebAssembly modules into a TinyWasm module. It is based on
3+
This crate provides a parser that can parse WebAssembly modules into a TinyWasm module. It is based on
44
[`wasmparser_nostd`](https://crates.io/crates/wasmparser_nostd) and used by [`tinywasm`](https://crates.io/crates/tinywasm).
55

66
## Features
@@ -11,11 +11,11 @@ This crate provides a parser that can parse WebAssembly modules into a TinyWasm
1111
## Usage
1212

1313
```rust
14-
use tinywasm_parser::{Parser, TinyWasmModule};
14+
use tinywasm_parser::Parser;
1515
let bytes = include_bytes!("./file.wasm");
1616

1717
let parser = Parser::new();
18-
let module: TinyWasmModule = parser.parse_module_bytes(bytes).unwrap();
19-
let mudule: TinyWasmModule = parser.parse_module_file("path/to/file.wasm").unwrap();
20-
let module: TinyWasmModule = parser.parse_module_stream(&mut stream).unwrap();
18+
let module = parser.parse_module_bytes(bytes).unwrap();
19+
let mudule = parser.parse_module_file("path/to/file.wasm").unwrap();
20+
let module = parser.parse_module_stream(&mut stream).unwrap();
2121
```

crates/tinywasm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pretty_env_logger="0.5"
3030

3131
[features]
3232
default=["std", "parser", "logging", "archive"]
33-
logging=["log", "tinywasm-types/logging", "tinywasm-parser?/logging"]
33+
logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"]
3434
std=["tinywasm-parser?/std", "tinywasm-types/std"]
3535
parser=["tinywasm-parser"]
3636
unsafe=["tinywasm-types/unsafe"]

crates/tinywasm/src/func.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ impl FuncHandle {
2929

3030
// 4. If the length of the provided argument values is different from the number of expected arguments, then fail
3131
if unlikely(func_ty.params.len() != params.len()) {
32-
log::info!("func_ty.params: {:?}", func_ty.params);
3332
return Err(Error::Other(format!(
3433
"param count mismatch: expected {}, got {}",
3534
func_ty.params.len(),

crates/tinywasm/src/imports.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ impl Imports {
286286
if let Some(v) = self.values.get(&name) {
287287
return Some(ResolvedExtern::Extern(v.clone()));
288288
}
289-
290289
if let Some(addr) = self.modules.get(&name.module) {
291290
let instance = store.get_module_instance(*addr)?;
292291
return Some(ResolvedExtern::Store(instance.export_addr(&import.name)?));
@@ -295,15 +294,11 @@ impl Imports {
295294
None
296295
}
297296

298-
fn compare_types<T>(import: &Import, actual: &T, expected: &T) -> Result<()>
299-
where
300-
T: Debug + PartialEq,
301-
{
297+
fn compare_types<T: Debug + PartialEq>(import: &Import, actual: &T, expected: &T) -> Result<()> {
302298
if expected != actual {
303299
log::error!("failed to link import {}, expected {:?}, got {:?}", import.name, expected, actual);
304300
return Err(LinkingError::incompatible_import_type(import).into());
305301
}
306-
307302
Ok(())
308303
}
309304

@@ -333,22 +328,20 @@ impl Imports {
333328
) -> Result<()> {
334329
Self::compare_types(import, &expected.arch, &actual.arch)?;
335330

336-
if actual.page_count_initial > expected.page_count_initial {
337-
if let Some(real_size) = real_size {
338-
if actual.page_count_initial > real_size as u64 {
339-
return Err(LinkingError::incompatible_import_type(import).into());
340-
}
341-
} else {
342-
return Err(LinkingError::incompatible_import_type(import).into());
343-
}
331+
if actual.page_count_initial > expected.page_count_initial
332+
&& real_size.map_or(true, |size| actual.page_count_initial > size as u64)
333+
{
334+
return Err(LinkingError::incompatible_import_type(import).into());
344335
}
345336

346-
match (expected.page_count_max, actual.page_count_max) {
347-
(None, Some(_)) => return Err(LinkingError::incompatible_import_type(import).into()),
348-
(Some(expected_max), Some(actual_max)) if actual_max < expected_max => {
349-
return Err(LinkingError::incompatible_import_type(import).into())
337+
if expected.page_count_max.is_none() && actual.page_count_max.is_some() {
338+
return Err(LinkingError::incompatible_import_type(import).into());
339+
}
340+
341+
if let (Some(expected_max), Some(actual_max)) = (expected.page_count_max, actual.page_count_max) {
342+
if actual_max < expected_max {
343+
return Err(LinkingError::incompatible_import_type(import).into());
350344
}
351-
_ => {}
352345
}
353346

354347
Ok(())

crates/tinywasm/src/instance.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,6 @@ impl ModuleInstance {
124124
&self.0.func_addrs
125125
}
126126

127-
/// Get the module's function types
128-
pub fn func_tys(&self) -> &[FuncType] {
129-
&self.0.types
130-
}
131-
132127
pub(crate) fn new(inner: ModuleInstanceInner) -> Self {
133128
Self(Rc::new(inner))
134129
}
@@ -232,7 +227,6 @@ impl ModuleInstance {
232227
///
233228
/// Returns None if the module has no start function
234229
/// If no start function is specified, also checks for a _start function in the exports
235-
/// (which is not part of the spec, but used by some compilers)
236230
///
237231
/// See <https://webassembly.github.io/spec/core/syntax/modules.html#start-function>
238232
pub fn start_func(&self, store: &Store) -> Result<Option<FuncHandle>> {

crates/tinywasm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
//! # Ok::<(), tinywasm::Error>(())
5959
//! ```
6060
//!
61+
//! For more examples, see the [`examples`](https://github.com/explodingcamera/tinywasm/tree/main/examples) directory.
62+
//!
6163
//! ## Imports
6264
//!
6365
//! To provide imports to a module, you can use the [`Imports`] struct.

crates/tinywasm/src/store/global.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ impl GlobalInstance {
3030
val.val_type()
3131
)));
3232
}
33+
3334
if !self.ty.mutable {
3435
return Err(Error::Other("global is immutable".to_string()));
3536
}
37+
3638
self.value = val.into();
3739
Ok(())
3840
}

crates/tinywasm/src/store/mod.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ mod function;
1717
mod global;
1818
mod memory;
1919
mod table;
20-
pub(crate) use data::*;
21-
pub(crate) use element::*;
22-
pub(crate) use function::*;
23-
pub(crate) use global::*;
24-
pub(crate) use memory::*;
25-
pub(crate) use table::*;
20+
pub(crate) use {data::*, element::*, function::*, global::*, memory::*, table::*};
2621

2722
// global store id counter
2823
static STORE_ID: AtomicUsize = AtomicUsize::new(0);
@@ -205,12 +200,11 @@ impl Store {
205200
let addr = globals.get(*addr as usize).copied().ok_or_else(|| {
206201
Error::Other(format!("global {} not found. This should have been caught by the validator", addr))
207202
})?;
208-
209203
let global = self.data.globals[addr as usize].clone();
210204
let val = i64::from(global.borrow().value);
211-
log::error!("global: {}", val);
205+
206+
// check if the global is actually a null reference
212207
if val < 0 {
213-
// the global is actually a null reference
214208
None
215209
} else {
216210
Some(val as u32)

crates/tinywasm/src/store/table.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
use crate::log;
2+
use crate::{Error, Result, Trap};
23
use alloc::{vec, vec::Vec};
3-
44
use tinywasm_types::*;
55

6-
use crate::{
7-
Error, Result, Trap,
8-
};
9-
106
const MAX_TABLE_SIZE: u32 = 10000000;
117

128
/// A WebAssembly Table Instance
@@ -30,7 +26,7 @@ impl TableInstance {
3026
Ok(match self.kind.element_type {
3127
ValType::RefFunc => val.map(WasmValue::RefFunc).unwrap_or(WasmValue::RefNull(ValType::RefFunc)),
3228
ValType::RefExtern => val.map(WasmValue::RefExtern).unwrap_or(WasmValue::RefNull(ValType::RefExtern)),
33-
_ => unimplemented!("unsupported table type: {:?}", self.kind.element_type),
29+
_ => Err(Error::UnsupportedFeature("non-ref table".into()))?,
3430
})
3531
}
3632

crates/tinywasm/tests/test-wast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ fn main() -> Result<()> {
1313
}
1414

1515
if args.len() < 3 {
16-
bail!("usage: cargo test-wast <wast-file>");
17-
}
16+
bail!("usage: cargo test-wast <wast-file>")
17+
};
1818

1919
// cwd for relative paths, absolute paths are kept as-is
2020
let cwd = std::env::current_dir()?;

crates/types/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
# `tinywasm_types`
1+
# `tinywasm-types`
22

3-
This crate contains the types used by the [`tinywasm`](https://crates.io/crates/tinywasm) crate. It is also used by the [`tinywasm_parser`](https://crates.io/crates/tinywasm_parser) crate to parse WebAssembly binaries.
3+
This crate contains the types used by the [`tinywasm`](https://crates.io/crates/tinywasm) crate. It is also used by the [`tinywasm-parser`](https://crates.io/crates/tinywasm-parser) crate to parse WebAssembly binaries.

crates/types/src/archive.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::fmt::{Display, Formatter};
2+
13
use crate::TinyWasmModule;
24
use rkyv::{
35
check_archived_root,
@@ -14,30 +16,49 @@ const TWASM_MAGIC: [u8; 16] = [ TWASM_MAGIC_PREFIX[0], TWASM_MAGIC_PREFIX[1], TW
1416

1517
pub use rkyv::AlignedVec;
1618

17-
fn validate_magic(wasm: &[u8]) -> Result<usize, &str> {
18-
if wasm.len() < TWASM_MAGIC.len() {
19-
return Err("Invalid twasm: too short");
20-
}
21-
if &wasm[..TWASM_MAGIC_PREFIX.len()] != TWASM_MAGIC_PREFIX {
22-
return Err("Invalid twasm: invalid magic number");
19+
fn validate_magic(wasm: &[u8]) -> Result<usize, TwasmError> {
20+
if wasm.len() < TWASM_MAGIC.len() || &wasm[..TWASM_MAGIC_PREFIX.len()] != TWASM_MAGIC_PREFIX {
21+
return Err(TwasmError::InvalidMagic);
2322
}
2423
if &wasm[TWASM_MAGIC_PREFIX.len()..TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()] != TWASM_VERSION {
25-
return Err("Invalid twasm: invalid version");
24+
return Err(TwasmError::InvalidVersion);
2625
}
2726
if wasm[TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()..TWASM_MAGIC.len()] != [0; 10] {
28-
return Err("Invalid twasm: invalid padding");
27+
return Err(TwasmError::InvalidPadding);
2928
}
3029

3130
Ok(TWASM_MAGIC.len())
3231
}
3332

33+
#[derive(Debug)]
34+
pub enum TwasmError {
35+
InvalidMagic,
36+
InvalidVersion,
37+
InvalidPadding,
38+
InvalidArchive,
39+
}
40+
41+
impl Display for TwasmError {
42+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
43+
match self {
44+
TwasmError::InvalidMagic => write!(f, "Invalid twasm: invalid magic number"),
45+
TwasmError::InvalidVersion => write!(f, "Invalid twasm: invalid version"),
46+
TwasmError::InvalidPadding => write!(f, "Invalid twasm: invalid padding"),
47+
TwasmError::InvalidArchive => write!(f, "Invalid twasm: invalid archive"),
48+
}
49+
}
50+
}
51+
52+
#[cfg(feature = "std")]
53+
impl std::error::Error for TwasmError {}
54+
3455
impl TinyWasmModule {
3556
/// Creates a TinyWasmModule from a slice of bytes.
36-
pub fn from_twasm(wasm: &[u8]) -> Result<TinyWasmModule, &str> {
57+
pub fn from_twasm(wasm: &[u8]) -> Result<TinyWasmModule, TwasmError> {
3758
let len = validate_magic(wasm)?;
38-
let root = check_archived_root::<Self>(&wasm[len..]).map_err(|e| {
39-
log::error!("Error checking archived root: {}", e);
40-
"Error checking archived root"
59+
let root = check_archived_root::<Self>(&wasm[len..]).map_err(|_e| {
60+
crate::log::error!("Invalid archive: {}", _e);
61+
TwasmError::InvalidArchive
4162
})?;
4263

4364
Ok(root.deserialize(&mut rkyv::Infallible).unwrap())

0 commit comments

Comments
 (0)