Browse Source

Expand top-level `wasmtime` crate docs (#1955)

This is something I meant to do a long time ago but forgot to get around
to it! This commit updates the top-level documentation of the `wasmtime`
crate to have examples, more words, and generall be a bit more
up-to-date and complete.
pull/1959/head
Alex Crichton 4 years ago
committed by GitHub
parent
commit
f24c7e1249
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Cargo.lock
  2. 1
      crates/wasmtime/Cargo.toml
  3. 233
      crates/wasmtime/src/lib.rs
  4. 24
      crates/wasmtime/src/runtime.rs

1
Cargo.lock

@ -2336,6 +2336,7 @@ dependencies = [
"wasmtime-jit",
"wasmtime-profiling",
"wasmtime-runtime",
"wasmtime-wasi",
"wat",
"winapi",
]

1
crates/wasmtime/Cargo.toml

@ -31,6 +31,7 @@ winapi = "0.3.7"
[dev-dependencies]
tempfile = "3.0"
wasmtime-wasi = { path = "../wasi" }
[badges]
maintenance = { status = "actively-developed" }

233
crates/wasmtime/src/lib.rs

@ -1,10 +1,233 @@
//! Wasmtime's embedding API
//!
//! This crate contains a high-level API used to interact with WebAssembly
//! modules. The API here is intended to mirror the proposed [WebAssembly C
//! API](https://github.com/WebAssembly/wasm-c-api), with small extensions here
//! and there to implement Rust idioms. This crate also defines the actual C API
//! itself for consumption from other languages.
//! This crate contains an API used to interact with WebAssembly modules. For
//! example you can compile modules, instantiate them, call them, etc. As an
//! embedder of WebAssembly you can also provide WebAssembly modules
//! functionality from the host by creating host-defined functions, memories,
//! globals, etc, which can do things that WebAssembly cannot (such as print to
//! the screen).
//!
//! The `wasmtime` crate draws inspiration from a number of sources, including
//! the [JS WebAssembly
//! API](https://developer.mozilla.org/en-US/docs/WebAssembly) as well as the
//! [proposed C API](https://github.com/webassembly/wasm-c-api). As with all
//! other Rust code you're guaranteed that programs will be safe (not have
//! undefined behavior or segfault) so long as you don't use `unsafe` in your
//! own program. With `wasmtime` you can easily and conveniently embed a
//! WebAssembly runtime with confidence that the WebAssembly is safely
//! sandboxed.
//!
//! An example of using Wasmtime looks like:
//!
//! ```
//! use anyhow::Result;
//! use wasmtime::*;
//!
//! fn main() -> Result<()> {
//! // All wasm objects operate within the context of a "store"
//! let store = Store::default();
//!
//! // Modules can be compiled through either the text or binary format
//! let wat = r#"
//! (module
//! (import "" "" (func $host_hello (param i32)))
//!
//! (func (export "hello")
//! i32.const 3
//! call $host_hello)
//! )
//! "#;
//! let module = Module::new(store.engine(), wat)?;
//!
//! // Host functions can be defined which take/return wasm values and
//! // execute arbitrary code on the host.
//! let host_hello = Func::wrap(&store, |param: i32| {
//! println!("Got {} from WebAssembly", param);
//! });
//!
//! // Instantiation of a module requires specifying its imports and then
//! // afterwards we can fetch exports by name, as well as asserting the
//! // type signature of the function with `get0`.
//! let instance = Instance::new(&store, &module, &[host_hello.into()])?;
//! let hello = instance
//! .get_func("hello")
//! .ok_or(anyhow::format_err!("failed to find `hello` function export"))?
//! .get0::<()>()?;
//!
//! // And finally we can call the wasm as if it were a Rust function!
//! hello()?;
//!
//! Ok(())
//! }
//! ```
//!
//! ## Core Concepts
//!
//! There are a number of core types and concepts that are important to be aware
//! of when using the `wasmtime` crate:
//!
//! * Reference counting - almost all objects in this API are reference counted.
//! Most of the time when and object is `clone`d you're just bumping a
//! reference count. For example when you clone an [`Instance`] that is a
//! cheap operation, it doesn't create an entirely new instance.
//!
//! * [`Store`] - all WebAssembly object and host values will be "connected" to
//! a store. A [`Store`] is not threadsafe which means that itself and all
//! objects connected to it are pinned to a single thread (this happens
//! automatically through a lack of the `Send` and `Sync` traits). Similarly
//! `wasmtime` does not have a garbage collector so anything created within a
//! [`Store`] will not be deallocated until all references have gone away. See
//! the [`Store`] documentation for more information.
//!
//! * [`Module`] - a compiled WebAssembly module. This structure represents
//! in-memory JIT code which is ready to execute after being instantiated.
//! It's often important to cache instances of a [`Module`] because creation
//! (compilation) can be expensive. Note that [`Module`] is safe to share
//! across threads.
//!
//! * [`Instance`] - an instantiated WebAssembly module. An instance is where
//! you can actually acquire a [`Func`] from, for example, to call. Each
//! [`Instance`], like all other [`Store`]-connected objects, cannot be sent
//! across threads.
//!
//! There are other important types within the `wasmtime` crate but it's crucial
//! to be familiar with the above types! Be sure to browse the API documentation
//! to get a feeling for what other functionality is offered by this crate.
//!
//! ## Example Architecture
//!
//! To better understand how Wasmtime types interact with each other let's walk
//! through, at a high-level, an example of how you might use WebAssembly. In
//! our use case let's say we have a web server where we'd like to run some
//! custom WebAssembly on each request. To ensure requests are isolated from
//! each other, though, we'll be creating a new [`Instance`] for each request.
//!
//! When the server starts, we'll start off by creating an [`Engine`] (and maybe
//! tweaking [`Config`] settings if necessary). This [`Engine`] will be the only
//! engine for the lifetime of the server itself.
//!
//! Next, we can compile our WebAssembly. You'd create a [`Module`] through the
//! [`Module::new`] API. This will generate JIT code and perform expensive
//! compilation tasks up-front.
//!
//! After that setup, the server starts up as usual and is ready to receive
//! requests. Upon receiving a request you'd then create a [`Store`] with
//! [`Store::new`] referring to the original [`Engine`]. Using your [`Module`]
//! from before you'd then call [`Instance::new`] to instantiate our module for
//! the request. Both of these operations are designed to be as cheap as
//! possible.
//!
//! With an [`Instance`] you can then invoke various exports and interact with
//! the WebAssembly module. Once the request is finished the [`Store`],
//! [`Instance`], and all other items loaded are dropped and everything will be
//! deallocated. Note that it's crucial to create a [`Store`]-per-request to
//! ensure that memory usage doesn't balloon accidentally by keeping a [`Store`]
//! alive indefinitely.
//!
//! ## Advanced Linking
//!
//! Often WebAssembly modules are not entirely self-isolated. They might refer
//! to quite a few pieces of host functionality, WASI, or maybe even a number of
//! other wasm modules. To help juggling all this together this crate provides a
//! [`Linker`] type which serves as an abstraction to assist in instantiating a
//! module. The [`Linker`] type also transparently handles Commands and Reactors
//! as defined by WASI.
//!
//! ## WASI
//!
//! The `wasmtime` crate does not natively provide support for WASI, but you can
//! use the `wasmtime-wasi` crate for that purpose. With `wasmtime-wasi` you can
//! create a "wasi instance" and then add all of its items into a [`Linker`],
//! which can then be used to instantiate a [`Module`] that uses WASI.
//!
//! ## Examples
//!
//! In addition to the examples below be sure to check out the [online embedding
//! documentation][rustdocs] as well as the [online list of examples][examples]
//!
//! [rustdocs]: https://bytecodealliance.github.io/wasmtime/lang-rust.html
//! [examples]: https://bytecodealliance.github.io/wasmtime/examples-rust-embed.html
//!
//! An example of using WASI looks like:
//!
//! ```no_run
//! # use anyhow::Result;
//! # use wasmtime::*;
//! use wasmtime_wasi::{Wasi, WasiCtx};
//!
//! # fn main() -> Result<()> {
//! let store = Store::default();
//! let mut linker = Linker::new(&store);
//!
//! // Create an instance of `Wasi` which contains a `WasiCtx`. Note that
//! // `WasiCtx` provides a number of ways to configure what the target program
//! // will have access to.
//! let wasi = Wasi::new(&store, WasiCtx::new(std::env::args())?);
//! wasi.add_to_linker(&mut linker)?;
//!
//! // Instantiate our module with the imports we've created, and run it.
//! let module = Module::from_file(store.engine(), "foo.wasm")?;
//! let instance = linker.instantiate(&module)?;
//! // ...
//!
//! # Ok(())
//! # }
//! ```
//!
//! An example of reading a string from a wasm module:
//!
//! ```
//! use std::str;
//!
//! # use wasmtime::*;
//! # fn main() -> anyhow::Result<()> {
//! let store = Store::default();
//! let log_str = Func::wrap(&store, |caller: Caller<'_>, ptr: i32, len: i32| {
//! let mem = match caller.get_export("memory") {
//! Some(Extern::Memory(mem)) => mem,
//! _ => return Err(Trap::new("failed to find host memory")),
//! };
//!
//! // We're reading raw wasm memory here so we need `unsafe`. Note
//! // though that this should be safe because we don't reenter wasm
//! // while we're reading wasm memory, nor should we clash with
//! // any other memory accessors (assuming they're well-behaved
//! // too).
//! unsafe {
//! let data = mem.data_unchecked()
//! .get(ptr as u32 as usize..)
//! .and_then(|arr| arr.get(..len as u32 as usize));
//! let string = match data {
//! Some(data) => match str::from_utf8(data) {
//! Ok(s) => s,
//! Err(_) => return Err(Trap::new("invalid utf-8")),
//! },
//! None => return Err(Trap::new("pointer/length out of bounds")),
//! };
//! assert_eq!(string, "Hello, world!");
//! println!("{}", string);
//! }
//! Ok(())
//! });
//! let module = Module::new(
//! store.engine(),
//! r#"
//! (module
//! (import "" "" (func $log_str (param i32 i32)))
//! (func (export "foo")
//! i32.const 4 ;; ptr
//! i32.const 13 ;; len
//! call $log_str)
//! (memory (export "memory") 1)
//! (data (i32.const 4) "Hello, world!"))
//! "#,
//! )?;
//! let instance = Instance::new(&store, &module, &[log_str.into()])?;
//! let foo = instance.get_func("foo").unwrap().get0::<()>()?;
//! foo()?;
//! # Ok(())
//! # }
//! ```
#![deny(missing_docs, intra_doc_link_resolution_failure)]
#![doc(test(attr(deny(warnings))))]

24
crates/wasmtime/src/runtime.rs

@ -784,11 +784,25 @@ impl Default for Engine {
// Store
/// A `Store` is a shared cache of information between WebAssembly modules.
///
/// Each `Module` is compiled into a `Store` and a `Store` is associated with an
/// [`Engine`]. You'll use a `Store` to attach to a number of global items in
/// the production of various items for wasm modules.
/// A `Store` is a collection of WebAssembly instances and host-defined items.
///
/// All WebAssembly instances and items will be attached to and refer to a
/// `Store`. For example instances, functions, globals, and tables are all
/// attached to a `Store`. Instances are created by instantiating a [`Module`]
/// within a `Store`.
///
/// `Store` is not thread-safe and cannot be sent to other threads. All items
/// which refer to a `Store` additionally are not threadsafe and can only be
/// used on the original thread that they were created on.
///
/// A `Store` is not intended to be a long-lived object in a program. No form of
/// GC is implemented at this time so once an instance is created within a
/// `Store` it will not be deallocated until all references to the `Store` have
/// gone away (this includes all references to items in the store). This makes
/// `Store` unsuitable for creating an unbounded number of instances in it
/// because `Store` will never release this memory. It's instead recommended to
/// have a long-lived [`Engine`] and instead create a `Store` for a more scoped
/// portion of your application.
///
/// # Stores and `Clone`
///

Loading…
Cancel
Save