Open john01dav opened 1 year ago
Look at this example examples/imports_function_env_global.rs
that does an import with store and all, and combine with examples/memory.rs
. We don't have an example that does exactly what you want yet, we might work on adding one later.
@ptitSeb i don't think imports_function_env_global
has an example of including the store in the env available to the functions when they run?
ah, i figured out that you can get store and data from the FunctionEnvMut
natively
I'm sorry if this is a bad place for this question. I would like to ask if this is the correct approach for reading memory from a host function. This code works but it seems weird to pass the memory into the FunctionEnv. Please excuse the unwraps and other bad code as this is just a quick proof of concept.
fn read_to_vec(view: &MemoryView, ptr: WasmPtr<u8>, len: u32) -> Vec<u8> {
let mut vec = Vec::with_capacity(len as usize);
for i in 0..len {
let a = ptr.add_offset(i).unwrap();
let b = a.read(&view).unwrap();
vec.push(b);
}
vec
}
// Wasm passes in a pointer + len to some data
fn host_fn(mut env: FunctionEnvMut<State>,ptr: WasmPtr<u8>, len: u32) -> u8 {
let (s, mut store) = env.data_and_store_mut();
let view = s.memory.as_ref().unwrap().view(&mut store);
let v = read_to_vec(&view, ptr, len);
// Adding 100 just to see that the call works
v[0] + 100
}
struct State {
memory: Option<Memory>
}
// Snip ... creating engine, store, loading wasm module from bytes
let env = FunctionEnv::new(&mut store, State { memory: None });
// Create an empty import object.
let import_object = imports! {
"env" => {
"host_fn" => Function::new_typed_with_env(&mut store, &env, host_fn)
}
};
let instance = Instance::new(&mut store, &module, &import_object)?;
let test_call: TypedFunction<(), ()> =
instance.exports.get_typed_function(&mut store, "test_call")?;
// Set memory before calling test_call
let memory = instance.exports.get_memory("memory")?;
env.as_mut(&mut store).memory = Some(memory.clone());
let result = test_call.call(&mut store, ()).unwrap();
assert_eq!(result, 223); // 123 + 100
The WASM compiled from rust
#[no_mangle]
pub unsafe extern "C" fn test_call() -> u8 {
let v2 = vec![123u8,2,3,4];
let result = host_fn(v2.as_ptr(), v2.len() as u32);
result
}
extern "C" {
pub fn host_fn(ptr: *const u8, len: u32) -> u8;
}
EDIT: in the process of writing a SO question I found this which suggest the same :) https://stackoverflow.com/questions/75753403/wasmer-host-functions-accessing-memory
In order to do most interesting things it is necessary to have an ABI that allows imported functions to read shared memory. For example, if the WASM code wants to pass a string to the host code it can give a pointer and length, which the host code can then read within the body of the imported function. But, when I am trying to write this, I am running into an issue. In order to get a MemoryView I need a & reference to the store, but I need to give a &mut reference to the store in Function::call or TypedFunction::call, which precludes having this & reference. How can I implement such an ABI?