Examples that show how to use Wasm multi-memory with Wasmi
#1774
Replies: 4 comments
-
|
Here is an example where a single Wasm module imports 2 linear memories which the host provides. use wasmi::{Engine, Instance, Memory, MemoryType, Module, Store};
#[test]
fn multi_memory() -> Result<(), wasmi::Error> {
let wasm = r#"
(module
(import "host" "mem0" (memory $mem0 1))
(import "host" "mem1" (memory $mem1 1))
(func (export "copy_from_mem0_to_mem1") (param $ptr i32)
(i32.store8 $mem1
(local.get $ptr)
(i32.load8_s $mem0 (local.get $ptr))
)
)
)
"#;
let engine = Engine::default();
let mut store = Store::new(&engine, ());
let mem0 = Memory::new(&mut store, MemoryType::new(1, None))?;
let mem1 = Memory::new(&mut store, MemoryType::new(1, None))?;
let module = Module::new(&engine, wasm)?;
let instance = Instance::new(&mut store, &module, &[mem0.into(), mem1.into()])?;
let copy_from_m0_to_m1 =
instance.get_typed_func::<i32, ()>(&mut store, "copy_from_mem0_to_mem1")?;
mem0.data_mut(&mut store)[42] = 100;
copy_from_m0_to_m1.call(&mut store, 42)?;
assert_eq!(mem1.data(&store)[42], 100);
Ok(())
}And here is an example that uses Wasmi's use wasmi::{Engine, Instance, Memory, MemoryType, Module, Store, Linker};
#[test]
fn multi_memory_using_linker() -> Result<(), wasmi::Error> {
let wasm = r#"
(module
(import "host" "mem0" (memory $mem0 1))
(import "host" "mem1" (memory $mem1 1))
(func (export "copy_from_mem0_to_mem1") (param $ptr i32)
(i32.store8 $mem1
(local.get $ptr)
(i32.load8_s $mem0 (local.get $ptr))
)
)
)
"#;
let engine = Engine::default();
let mut store = Store::new(&engine, ());
let mem0 = Memory::new(&mut store, MemoryType::new(1, None))?;
let mem1 = Memory::new(&mut store, MemoryType::new(1, None))?;
let module = Module::new(&engine, wasm)?;
let mut linker = <Linker<()>>::new(&engine);
linker.define("host", "mem0", mem0)?;
linker.define("host", "mem1", mem1)?;
let instance = linker.instantiate_and_start(&mut store, &module)?;
let copy_from_m0_to_m1 =
instance.get_typed_func::<i32, ()>(&mut store, "copy_from_mem0_to_mem1")?;
mem0.data_mut(&mut store)[42] = 100;
copy_from_m0_to_m1.call(&mut store, 42)?;
assert_eq!(mem1.data(&store)[42], 100);
Ok(())
}Wasm module in isolation for syntax highlighting: (module
(import "host" "mem0" (memory $mem0 1))
(import "host" "mem1" (memory $mem1 1))
(func (export "copy_from_mem0_to_mem1") (param $ptr i32)
(i32.store8 $mem1
(local.get $ptr)
(i32.load8_s $mem0 (local.get $ptr))
)
)
) |
Beta Was this translation helpful? Give feedback.
-
|
I opened a PR that adds these examples to the repo: #1775 Run them via: |
Beta Was this translation helpful? Give feedback.
-
|
And here are the same examples where the Wasm module itself defines the two linear memories: use wasmi::{Engine, Instance, Linker, Module, Store};
/// A Wasm module that imports 2 Wasm memories and exports a function
/// that copies a single byte from `mem0` to `mem1`.
const WASM: &str = r#"
(module
(memory $mem0 (export "mem0") 1)
(memory $mem1 (export "mem1") 1)
(func (export "copy_from_mem0_to_mem1") (param $ptr i32)
(i32.store8 $mem1
(local.get $ptr)
(i32.load8_s $mem0 (local.get $ptr))
)
)
)
"#;
fn common_setup() -> Result<(Store<()>, Module), wasmi::Error> {
let engine = Engine::default();
let store = Store::new(&engine, ());
let module = Module::new(&engine, WASM)?;
Ok((store, module))
}
#[test]
fn multi_memory_using_instance_new() -> Result<(), wasmi::Error> {
let (mut store, module) = common_setup()?;
let instance = Instance::new(&mut store, &module, &[])?;
test_copying_works(&mut store, &instance, 42)
}
#[test]
fn multi_memory_using_linker() -> Result<(), wasmi::Error> {
let (mut store, module) = common_setup()?;
let linker = <Linker<()>>::new(store.engine());
let instance = linker.instantiate_and_start(&mut store, &module)?;
test_copying_works(&mut store, &instance, 42)
}
fn test_copying_works(
store: &mut Store<()>,
instance: &Instance,
ptr: usize,
) -> Result<(), wasmi::Error> {
let copy_from_m0_to_m1 =
instance.get_typed_func::<u32, ()>(&mut *store, "copy_from_mem0_to_mem1")?;
let mem0 = instance.get_memory(&*store, "mem0").unwrap();
let mem1 = instance.get_memory(&*store, "mem1").unwrap();
assert_eq!(mem1.data(&store)[ptr], 0);
mem0.data_mut(&mut *store)[ptr] = 100;
copy_from_m0_to_m1.call(&mut *store, ptr as u32)?;
assert_eq!(mem1.data(&store)[ptr], 100);
Ok(())
}With the following Wasm file for syntax highlighting: (module
(memory $mem0 (export "mem0") 1)
(memory $mem1 (export "mem1") 1)
(func (export "copy_from_mem0_to_mem1") (param $ptr i32)
(i32.store8 $mem1
(local.get $ptr)
(i32.load8_s $mem0 (local.get $ptr))
)
)
) |
Beta Was this translation helpful? Give feedback.
-
|
Thank you! Somewhat outside the scope of wasmi, but do you know if the Rust WASM toolchain currently supports use (import or export, or both) of multiple memories by the guest? In these examples, the guest is written in WAT, I'm curious to know what this would look like written in Rust, if that's even possible? Even a single memory needs special linker flags, AFAICT. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Are there any working examples for the multi-memory feature implemented in #776?
At the moment, with a single region, I'm using linker flags to import the host-created region, and I imagine that multiple regions may need more elaborate linker flags?
How does a host export multiple memory regions, (and how does a guest, written in Rust, import these)?
If a guest exports multiple memory regions, how does a host, written in Rust using Wasmi, get access to all of these regions? Does the API support the host obtaining handles to these guest-created regions?
Beta Was this translation helpful? Give feedback.
All reactions