8 releases
0.3.1 | Nov 12, 2024 |
---|---|
0.3.0 | Jul 23, 2024 |
0.2.0 | Feb 27, 2024 |
0.1.4 | Oct 27, 2023 |
0.1.1 | Mar 28, 2023 |
#515 in WebAssembly
52 downloads per month
Used in wasefire-scheduler
170KB
4K
SLoC
WebAssembly interpreter with customizable trade-off between footprint and performance.
The main concepts of this crate are:
-
A
Store
contains instantiated modules and permits execution. Note that execution within the same store must follow a stack behavior. A function "bar" may be called while a function "foo" is running: "bar" will temporarily interrupt "foo" until "bar" returns at which point "foo" would resume. This is to avoid corrupting the stack within the same instance. Once the WebAssembly threads proposal lands, this restriction may be removed. -
A
Module
represents a valid module. Only valid modules may be instantiated. A module is just a byte slice holding a WebAssembly module in binary format. -
A
RunResult
represents the result of a (possibly partial) execution. When invoking an exported function from an instance in a store, or when resuming the execution after a call to the host, aRunResult
is returned providing either the next call to the host or whether execution of the most recently invoked function terminated along with its results.
Examples
For a concrete "hello" example, see examples/hello.rs
which walks through most important steps
in using this crate. Otherwise, here are some short excerpts:
Creating a store can simply use the Default
trait:
let mut store = Store::default();
Linking a host function in a store is done with [Store::link_func()
]:
store.link_func("env", "add", 2, 1)?;
Instantiating a valid module in a store is done with [Store::instantiate()
]:
let inst = store.instantiate(module, memory)?;
Invoking a function exported by an instance is done with [Store::invoke()
]:
let mut result = store.invoke(inst, "mul", vec![Val::I32(13), Val::I32(29)])?;
Processing a call to the host is done with the Call
in RunResult::Host
:
loop {
let mut call = match result {
RunResult::Done(results) => return Ok(results),
RunResult::Host(call) => call,
};
let results = process(&mut call)?;
result = call.resume(&results)?;
}
Atomic support
This crate uses atomic operations and relies on the portable-atomic
crate to support
architectures without atomic operations. Depending on your architecture, you may need one of the
following:
-
Enable the
portable-atomic/critical-section
feature (possibly adding a direct dependency onportable-atomic
). -
Set the
--cfg=portable_atomic_unsafe_assume_single_core
rustc flag.
You can find more information in the portable-atomic
documentation.
Dependencies
~1.3–2MB
~39K SLoC