tinywasm

repository·next·Indexed 20 days ago

https://github.com/explodingcamera/tinywasm

A small, portable, and safe WebAssembly runtime written in Rust, designed for both standard and no_std environments. It features a minimal footprint, a CLI for module execution and inspection, and a custom internal bytecode format called twasm for optimized loading. The runtime supports various Wasm proposals including Multi-value, Bulk Memory Operations, and Fixed-Width SIMD, and provides configurable memory backends such as VecMemory and PagedMemory.

Tokens
25.3K
Snippets
77
Records
117
Agent score
69%

What's inside tinywasm

  1. How TinyWasm's internal bytecode and execution works

    next

    TinyWasm does not interpret WebAssembly instructions directly. Instead, it follows a multi-stage process to optimize execution:

    1. Parsing & Validation: WebAssembly is translated into a compact internal bytecode format.
    2. Lowering: Structured control flow (like block, loop, if, br*) is resolved ahead of time into jump-oriented instructions such as Jump, JumpIfZero, BranchTable*, DropKeep*, and Return.
    3. Optimization: A peephole optimizer (optimize.rs) performs superinstruction fusion. It combines common sequences (like binary operations with local access or comparisons with conditional branches) into single instructions to reduce interpreter dispatch overhead.
    4. Execution: The runtime uses a single iterative interpreter loop over the lowered, optimized instruction stream.

    This architecture allows modules to be optionally serialized as .twasm files for faster reuse, as the heavy lifting of parsing and lowering is already complete.

  2. When to use `tinywasm-types`

    next

    tinywasm-types is a specialized crate containing shared module, instruction, value, and archive types used by both tinywasm and tinywasm-parser.

    Most users should depend on tinywasm directly.

    You should only use tinywasm-types if you need to:

    • Work with parsed modules.
    • Work with serialized twasm archives.
    • Access shared type definitions without pulling in the full tinywasm runtime.
  3. Understand the twasm bytecode format

    next

    TinyWasm uses an internal bytecode format called twasm.

    Benefits:

    • Stores optimized instruction representations for faster loading and reuse.
    • Modules can be compiled to twasm ahead of time.

    Security Warning:

    • The twasm format is not currently validated as an untrusted input format. Malformed twasm may cause a panic, though it is designed not to compromise memory safety or allow sandbox escapes. Only run trusted twasm bytecode or bytecode generated by TinyWasm itself.
  4. API stability in `tinywasm-types`

    next

    The tinywasm-types crate is semver-exempt. This means it may introduce breaking API changes in any release.

    Note on Compatibility: If you are using types re-exported by the tinywasm crate, those types remain covered by tinywasm's compatibility policy. However, if you depend on tinywasm-types directly, you must be prepared for breaking changes.

  5. Understand TinyWasm's runtime layout and value stacks

    next

    TinyWasm manages values using untyped stacks categorized by bit-width to optimize storage:

    • stack_32: Stores i32, f32, funcref, and externref.
    • stack_64: Stores i64 and f64.
    • stack_128: Stores v128.

    Locals are stored directly within these value stacks. Each CallFrame maintains a locals_base pointer, and local instructions use indices relative to that base.

  6. Install the tinywasm CLI

    next

    You can install the tinywasm binary using cargo install. It is recommended to use the tinywasm library directly for embedding in your own projects, but the CLI is useful for manual execution and testing.

    To install the CLI version 0.9.0 specifically, use the following command:

    $ cargo install tinywasm-cli --version 0.9.0 --bin tinywasm
  7. Parse WebAssembly modules with `tinywasm-parser`

    next

    Use tinywasm-parser to convert WebAssembly binaries into tinywasm modules. You can use the high-level Parser struct for fine-grained control or top-level helper functions for default configurations.

    Using the Parser struct

    To use custom configurations, instantiate a Parser and use its methods:

    • parse_module_bytes(bytes): Parses from a byte slice.
    • parse_module_file(path): Parses from a file path.
    • parse_module_stream(stream): Parses from an object implementing std::io::Read.

    You can configure the parser using Parser::with_options(ParserOptions) to adjust settings like rewrite optimizations.

    Using top-level helpers

    For default settings, use the following thin wrappers:

    • parse_bytes(bytes)
    • parse_file(path)
    • parse_stream(stream)
    use tinywasm_parser::{Parser, ParserOptions};
    
    let bytes = include_bytes!("./file.wasm");
    
    // Default parser
    let parser = Parser::new();
    let module = parser.parse_module_bytes(bytes)?;
    
    // Parser with custom options
    let parser = Parser::with_options(ParserOptions::default().with_rewrite_optimization(false));
    let module = parser.parse_module_bytes(bytes)?;
    
    // Parsing from a file
    let module = parser.parse_module_file("path/to/file.wasm")?;
    
    // Parsing from a stream
    let mut stream = std::fs::File::open("path/to/file.wasm")?;
    let module = parser.parse_module_stream(&mut stream)?;
  8. Use the tinywasm CLI for module execution and inspection

    next

    The tinywasm CLI provides several commands for running, compiling, and inspecting WebAssembly modules.

    Supported File Formats

    The run, dump, and inspect commands accept .wasm, .wat, and .twasm inputs.

    Common Commands

    • Run a module: tinywasm ./module.wasm. Without the --invoke flag, the CLI expects the module to have a start function or a _start export.
    • Invoke a specific function: tinywasm run --invoke <name> <path> <args...>. Arguments are automatically parsed based on the function's export signature, so you do not need to specify types.
    • Compile to Twasm: tinywasm compile ./module.wat -o ./module.twasm. This writes the TinyWasm twasm archive format.
    • Dump module contents: tinywasm dump ./module.twasm.
    • Inspect a module: tinywasm inspect ./module.wasm. This uses ANSI colors by default; set NO_COLOR=1 to disable them.
    • Run WASM spec tests: tinywasm wast <path> (accepts files or folders containing .wast files).

    Input via Stdin

    You can use - as the input path to read a module from standard input.

    $ tinywasm --help
    $ tinywasm ./module.wasm
    $ tinywasm run --invoke add ./module.wasm 1 2
    $ tinywasm compile ./module.wat -o ./module.twasm
    $ tinywasm dump ./module.twasm
    $ tinywasm inspect ./module.wasm
    $ tinywasm wast ./spec-tests/address.wast
  9. Build the WebAssembly Rust examples

    next

    To build the WebAssembly artifacts required for the wasm-rust example, run the provided build script. This process requires the wasm32-unknown-unknown Rust target, as well as the binaryen and wabt toolchains to be installed on your system.

    To run the example after building, use: cargo run --example wasm-rust -- <name>

    ./examples/rust/build.sh
    # Then run the example:
    cargo run --example wasm-rust -- <name>