summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/lib.rs10
-rw-r--r--crates/tinywasm/src/engine.rs17
-rw-r--r--crates/tinywasm/src/func.rs26
-rw-r--r--crates/tinywasm/src/instance.rs4
-rw-r--r--crates/tinywasm/src/lib.rs58
-rw-r--r--crates/tinywasm/src/reference.rs23
-rw-r--r--crates/tinywasm/src/store/memory/mod.rs6
-rw-r--r--crates/types/src/archive.rs5
-rw-r--r--crates/types/src/instructions.rs7
-rw-r--r--crates/types/src/lib.rs6
10 files changed, 112 insertions, 50 deletions
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 7936675..aa5e0b0 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -49,7 +49,10 @@ pub use tinywasm_types::Module;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct ParserOptions {
- /// Whether to validate modules while parsing.
+ /// Whether to validate modules while parsing. Enabled by default.
+ ///
+ /// Disable this only for trusted input. Parsing without validation may produce
+ /// a module that violates runtime assumptions.
pub validation: bool,
/// Whether to optimize local memory allocation by skipping allocation of unused local memories.
pub optimize_local_memory_allocation: bool,
@@ -81,6 +84,9 @@ impl Default for ParserOptions {
impl ParserOptions {
/// Enable or disable WebAssembly validation.
+ ///
+ /// Disable this only for trusted input. Parsing without validation may produce
+ /// a module that violates runtime assumptions.
pub const fn with_validation(mut self, enabled: bool) -> Self {
self.validation = enabled;
self
@@ -337,7 +343,7 @@ pub fn parse_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Mo
}
#[cfg(feature = "std")]
-/// Parse a module from a stream. Requires `parser` and `std` features.
+/// Parse a module from a stream. Requires the `std` feature.
pub fn parse_stream(stream: impl crate::std::io::Read) -> Result<Module> {
Parser::new().parse_module_stream(stream)
}
diff --git a/crates/tinywasm/src/engine.rs b/crates/tinywasm/src/engine.rs
index dfb4d15..521eb80 100644
--- a/crates/tinywasm/src/engine.rs
+++ b/crates/tinywasm/src/engine.rs
@@ -92,7 +92,10 @@ impl StackConfig {
///
/// let config = Config::new()
/// .with_fuel_policy(FuelPolicy::Weighted)
-/// .with_value_stack(StackConfig::dynamic(1024, 16 * 1024))
+/// .with_value_stack_32(StackConfig::dynamic(1024, 36 * 1024))
+/// .with_value_stack_64(StackConfig::dynamic(1024, 32 * 1024))
+/// .with_value_stack_128(StackConfig::dynamic(256, 4 * 1024))
+/// .with_call_stack(StackConfig::dynamic(64, 1024))
/// .with_memory_backend(MemoryBackend::paged(64 * 1024))
/// .with_trap_on_oom(true);
///
@@ -103,23 +106,27 @@ impl StackConfig {
#[non_exhaustive]
pub struct Config {
/// Configuration for the 32-bit value stack (i32, f32, ref values).
+ /// Defaults to `StackConfig::fixed(36 * 1024)`.
pub value_stack_32: StackConfig,
/// Configuration for the 64-bit value stack (i64, f64 values).
+ /// Defaults to `StackConfig::fixed(32 * 1024)`.
pub value_stack_64: StackConfig,
/// Configuration for the 128-bit value stack (v128 values).
+ /// Defaults to `StackConfig::fixed(4 * 1024)`.
pub value_stack_128: StackConfig,
- /// Configuration for the call stack.
+ /// Configuration for the call stack. Defaults to `StackConfig::fixed(1024)`.
pub call_stack: StackConfig,
- /// Fuel accounting policy used by budgeted execution.
+ /// Fuel accounting policy used by budgeted execution. Defaults to [`FuelPolicy::PerInstruction`].
pub fuel_policy: FuelPolicy,
- /// Backend used for runtime memories.
+ /// Backend used for runtime memories. Defaults to [`MemoryBackend::vec`].
pub memory_backend: MemoryBackend,
/// Whether memory and stack allocation failures should trap instead of degrading into normal operation failure modes.
+ /// Defaults to `false`.
pub trap_on_oom: bool,
}
impl Config {
- /// Create a new stack configuration with default settings.
+ /// Create a new interpreter configuration with default settings.
pub fn new() -> Self {
Self::default()
}
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 9777a47..05767d5 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -47,7 +47,7 @@ impl Function {
///
/// The returned handle keeps a mutable borrow of the [`Store`] until it
/// completes. Use [`FuncExecution::resume_with_fuel`] (or
- /// [`FuncExecution::resume_with_time_budget`] with `std`) to continue.
+ /// `resume_with_time_budget` with `std`) to continue.
pub fn call_resumable<'store>(
&self,
store: &'store mut Store,
@@ -540,6 +540,25 @@ impl<P: IntoWasmValues, R: FromWasmValues> FunctionTyped<P, R> {
/// Call a typed function and return a resumable execution handle.
///
/// The handle keeps a mutable borrow of the [`Store`] until completion.
+ ///
+ /// ## Example
+ ///
+ /// ```rust
+ /// # fn main() -> tinywasm::Result<()> {
+ /// use tinywasm::{ExecProgress, ModuleInstance, Store};
+ ///
+ /// let wasm = include_bytes!("../../../examples/wasm/add.wasm");
+ /// let module = tinywasm::parse_bytes(wasm)?;
+ /// let mut store = Store::default();
+ /// let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
+ /// let add = instance.func::<(i32, i32), i32>(&store, "add")?;
+ ///
+ /// let mut execution = add.call_resumable(&mut store, (20, 22))?;
+ /// assert!(matches!(execution.resume_with_fuel(0)?, ExecProgress::Suspended));
+ /// assert!(matches!(execution.resume_with_fuel(16)?, ExecProgress::Completed(42)));
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn call_resumable<'store>(&self, store: &'store mut Store, params: P) -> Result<FuncExecutionTyped<'store, R>> {
let wasm_values = params.into_wasm_values();
let execution = self.func.call_resumable(store, &wasm_values)?;
@@ -574,7 +593,10 @@ impl<'store, R: FromWasmValues> FuncExecutionTyped<'store, R> {
/// Describes the WebAssembly value types produced by a Rust value or tuple shape.
pub trait ToWasmTypes {
- /// Static WebAssembly types for shapes that do not require runtime concatenation.
+ /// Static WebAssembly types for this shape.
+ ///
+ /// Implementations that require runtime construction may set this to `None`,
+ /// but must then override [`Self::wasm_types`].
const WASM_TYPES: Option<&'static [WasmType]>;
/// Return the flattened WebAssembly value types for this tuple shape.
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 8cff310..a727638 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -560,8 +560,8 @@ impl ModuleInstance {
/// Get the start function of the module
///
- /// Returns None if the module has no start function
- /// If no start function is specified, also checks for a `_start` function in the exports
+ /// Returns `None` if the module has no start section. Exported functions named
+ /// `_start` are not treated as the module's start function.
///
/// ## Example
/// ```rust
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index a48d9d7..908f33b 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -9,42 +9,22 @@
//! `tinywasm` provides a small, portable WebAssembly interpreter with support for
//! the WebAssembly MVP, WebAssembly 2.0, and a growing set of newer proposals.
+//! It also supports the [Lime1](https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md#lime1)
+//! interoperability target.
//! It is designed to stay lightweight while still being practical to embed in
//! applications, tools, and `no_std + alloc` environments.
-//!
-//! ## Features
-//! - **`std`**\
-//! Enables parsing from files and streams. Enabled by default.
-//! - **`log`**\
-//! Enables integration with the `log` crate. Enabled by default.
-//! - **`parser`**\
-//! Enables the bundled `tinywasm-parser` crate and top-level parse helpers. Enabled by default.
-//! - **`archive`**\
-//! Enables serialization and deserialization of compiled modules in the internal `twasm` format. Enabled by default.
-//! - **`canonicalize-nans`**\
-//! Canonicalizes NaN values to a single representation. Enabled by default.
-//! - **`debug`**\
-//! Derives `Debug` for runtime types. Enabled by default.
-//! - **`parallel-parser`**\
-//! Parallelizes function parsing and validation across threads when `std` is enabled. Enabled by default.
-//! - **`guest-debug`**\
-//! Exposes module-internal by-index inspection APIs (`*_by_index`).
-//! - **`simd-x86`**\
-//! Enables x86-specific SIMD intrinsics for selected operations and uses `unsafe` internally.
-//!
-//! With default features disabled, `tinywasm` only depends on `core`, `alloc`, and `libm`.
-//! By disabling `std`, you can use `tinywasm` in `no_std` environments. This requires
-//! a custom allocator and removes support for parsing from files and streams, but otherwise the API is the same.
#![cfg_attr(docsrs, feature(doc_cfg))]
//!
-//! ## Getting Started
-//! The easiest way to get started is to use the [`crate::parse_bytes`] function to load a
+//! ## Getting started
+//!
+//! The easiest way to get started is to use the `parse_bytes` function to load a
//! WebAssembly module from bytes. This will parse the module and validate it, returning
//! a [`Module`] that can be used to instantiate the module.
//!
-//!
//! ```rust
+//! # #[cfg(feature = "parser")]
+//! # fn main() -> tinywasm::Result<()> {
//! use tinywasm::{ModuleInstance, Store};
//!
//! // Load a module from bytes
@@ -62,12 +42,15 @@
//!
//! // # Get a typed handle to the exported "add" function
//! // Alternatively, you can use `instance.func_untyped` to get an untyped handle
-//! // that takes and returns [`WasmValue`]s
-//! let func = instance.func::<(i32, i32), i32>(&mut store, "add")?;
+//! // that takes and returns [`types::WasmValue`]s
+//! let func = instance.func::<(i32, i32), i32>(&store, "add")?;
//! let res = func.call(&mut store, (1, 2))?;
//!
//! assert_eq!(res, 3);
-//! # Ok::<(), tinywasm::Error>(())
+//! # Ok(())
+//! # }
+//! # #[cfg(not(feature = "parser"))]
+//! # fn main() {}
//! ```
//!
//! For non-default runtime behavior, construct a [`Store`] with a custom [`Engine`]
@@ -76,6 +59,21 @@
//!
//! For more examples, see the [`examples`](https://github.com/explodingcamera/tinywasm/tree/main/examples) directory.
//!
+//! ## Cargo features
+//!
+//! - **`std`:** Enables `std` and parsing from files and streams. Enabled by default.
+//! - **`log`:** Enables integration with the `log` crate. Enabled by default.
+//! - **`parser`:** Enables `tinywasm-parser` and top-level parse helpers. Enabled by default.
+//! - **`archive`:** Enables serialization and deserialization of the internal `twasm` format. Enabled by default.
+//! - **`canonicalize-nans`:** Canonicalizes NaN values. Enabled by default.
+//! - **`debug`:** Derives `Debug` for runtime types. Enabled by default.
+//! - **`parallel-parser`:** Parallelizes function parsing and validation when `std` is enabled. Enabled by default.
+//! - **`guest-debug`:** Exposes module-internal by-index inspection APIs (`*_by_index`).
+//! - **`simd-x86`:** Enables x86-specific SIMD intrinsics and uses `unsafe` internally.
+//!
+//! With default features disabled, `tinywasm` depends only on `core`, `alloc`, and `libm`,
+//! making it usable in `no_std + alloc` environments with a custom allocator.
+//!
//! ## Imports
//!
//! To provide imports to a module, you can use the [`Imports`] struct.
diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs
index e46db51..004939f 100644
--- a/crates/tinywasm/src/reference.rs
+++ b/crates/tinywasm/src/reference.rs
@@ -167,6 +167,29 @@ impl Memory {
/// Creates a cursor positioned at the start of this memory.
///
/// Available with the `std` feature enabled.
+ ///
+ /// ## Example
+ ///
+ /// ```rust
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use std::io::{Read, Seek, SeekFrom, Write};
+ /// use tinywasm::types::MemoryType;
+ /// use tinywasm::{Memory, Store};
+ ///
+ /// let mut store = Store::default();
+ /// let memory = Memory::new(&mut store, MemoryType::default().with_page_count_initial(1))?;
+ /// let mut cursor = memory.cursor(&mut store)?;
+ ///
+ /// cursor.seek(SeekFrom::Start(2))?;
+ /// cursor.write_all(b"abc")?;
+ /// cursor.seek(SeekFrom::Start(0))?;
+ ///
+ /// let mut bytes = [0; 5];
+ /// cursor.read_exact(&mut bytes)?;
+ /// assert_eq!(bytes, [0, 0, b'a', b'b', b'c']);
+ /// # Ok(())
+ /// # }
+ /// ```
#[cfg(feature = "std")]
pub fn cursor<'a>(&self, store: &'a mut Store) -> Result<MemoryCursor<'a>> {
self.cursor_at(store, 0)
diff --git a/crates/tinywasm/src/store/memory/mod.rs b/crates/tinywasm/src/store/memory/mod.rs
index aeaf3ba..a3f0053 100644
--- a/crates/tinywasm/src/store/memory/mod.rs
+++ b/crates/tinywasm/src/store/memory/mod.rs
@@ -23,6 +23,7 @@ pub use {lazy::LazyLinearMemory, paged::PagedMemory, vec_memory::VecMemory};
/// This is a low-level trait that abstracts over the actual storage mechanism for linear memory.
/// This will probably change in the future to allow more efficient implementations.
/// See [`MemoryBackend`] for a higher-level interface to configuring memory storage.
+/// The runtime passes slices of the exact indicated width to the fixed-width `write_*` methods.
pub trait LinearMemory {
/// Returns the current memory length in bytes.
fn len(&self) -> usize;
@@ -285,12 +286,13 @@ impl MemoryBackend {
/// Uses sparse chunked storage for each memory instance.
///
- /// `chunk_size` is the backend chunk size in bytes. It is independent from the Wasm page size.
+ /// `chunk_size` is the backend chunk size in bytes. It must be a non-zero power
+ /// of two and is independent from the Wasm page size.
///
/// This generally makes growth cheaper than [`Self::vec`], but read and write operations do a
/// little more work and may be slightly slower.
pub fn paged(chunk_size: usize) -> Self {
- assert!(chunk_size != 0, "chunk_size must be greater than zero");
+ assert!(chunk_size.is_power_of_two(), "chunk_size must be a non-zero power of two");
Self(MemoryBackendInner::Paged { chunk_size })
}
diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs
index 48dc53f..99238ab 100644
--- a/crates/types/src/archive.rs
+++ b/crates/types/src/archive.rs
@@ -45,7 +45,10 @@ impl Display for TwasmError {
impl core::error::Error for TwasmError {}
impl Module {
- /// Creates a [`Module`] from a slice of bytes.
+ /// Creates a [`Module`] from internal `twasm` archive bytes.
+ ///
+ /// Archives are version-specific and are not validated as untrusted input.
+ /// Only load archives from a trusted source.
pub fn try_from_twasm(wasm: &[u8]) -> Result<Self, TwasmError> {
let len = validate_magic(wasm)?;
postcard::from_bytes(&wasm[len..]).map_err(TwasmError::InvalidArchive)
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index a22279e..cec9d5b 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -116,10 +116,11 @@ pub enum BinOp128 {
I64x2Mul,
}
-/// A WebAssembly Instruction
+/// A TinyWasm bytecode instruction.
///
-/// These are our own internal bytecode instructions so they may not match the spec exactly.
-/// Wasm Bytecode can map to multiple of these instructions.
+/// These instructions are an internal, version-specific representation and do not
+/// map one-to-one to WebAssembly instructions. Their variants and serialized form
+/// may change between TinyWasm releases.
///
/// See <https://webassembly.github.io/spec/core/binary/instructions.html>
#[rustfmt::skip]
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index fcac23c..0b4b54c 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -45,8 +45,8 @@ pub mod archive {
/// A `TinyWasm` WebAssembly Module
///
/// This is the internal representation of a WebAssembly module in `TinyWasm`.
-/// [`Module`] are validated before being created, so they are guaranteed to be valid (as long as they were created by `TinyWasm`).
-/// This means you should not trust a [`Module`] created by a third party to be valid.
+/// Modules produced by the parser are validated by default, but validation can be
+/// disabled for trusted input. Do not trust modules or archives from third parties.
#[derive(Clone, Default, PartialEq)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
@@ -76,7 +76,7 @@ pub struct ModuleInner {
/// Corresponds to the `start` section of the original WebAssembly module.
pub start_func: Option<FuncAddr>,
- /// Optimized and validated WebAssembly functions
+ /// Optimized WebAssembly functions
///
/// Contains data from to the `code`, `func`, and `type` sections of the original WebAssembly module.
pub funcs: Box<[Arc<WasmFunction>]>,