Last active
April 25, 2020 04:23
-
-
Save Redrield/49bfcfea48985fa0885d04d658cb211b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use wasmtime::*; | |
use wasmtime_wasi::*; | |
pub struct PluginInstance { | |
inst: Instance, | |
buf_ptr_base: i32, | |
buf_pool_size: usize, | |
write_offset: isize, | |
} | |
impl PluginInstance { | |
pub fn new(inst: Instance) -> PluginInstance { | |
// The exported memory is used by the plugins libstd allocator for heap structures | |
// so the best way to make sure that a region of memory wont interfere with structures | |
// that a plugin may be allocating is to let it give us the pointer, and make sure to | |
// remain in the asked for bounds when interacting with plugin memory | |
let alloc = inst.get_export("alloc_runtime_buffer").unwrap().func().unwrap(); | |
let ret = alloc.call(&[Val::I32(1024)]).unwrap()[0].clone(); | |
let ptr = ret.unwrap_i32(); | |
println!("Host has 0x{:x}..0x{:x} to play with", ptr, ptr + 1024); | |
PluginInstance { | |
inst, | |
buf_ptr_base: ptr, | |
buf_pool_size: 1024, | |
write_offset: 0, | |
} | |
} | |
pub fn write_object_to_memory(&mut self, buf: &[u8]) -> (i32, i32) { | |
// Make sure we wont overflow our buffer | |
if self.buf_ptr_base + self.write_offset as i32 > self.buf_ptr_base + self.buf_pool_size as i32{ | |
panic!("Out of mem"); | |
} | |
let mem = self.inst.get_export("memory").unwrap().memory().unwrap(); | |
unsafe { | |
// Get the write pointer based on our offset into WASM memory, and the offset into our buffer we've written to | |
let ptr = mem.data_ptr().offset(self.buf_ptr_base as isize + self.write_offset); | |
ptr.copy_from(buf.as_ptr(), buf.len()); | |
} | |
// Keep track of where the newly written data starts, and increment the write offset by the data written | |
let ptr_handle = self.buf_ptr_base + self.write_offset as i32; | |
self.write_offset += buf.len() as isize; | |
(ptr_handle, buf.len() as i32) | |
} | |
pub fn call_function(&self, name: &str, args: &[Val]) -> Result<Box<[Val]>, Trap> { | |
let func = self.inst.get_export(name).unwrap().func().unwrap(); | |
func.call(args) | |
} | |
} | |
fn main() { | |
let store = Store::default(); | |
let module = Module::from_file(&store, "./target/wasm32-wasi/debug/plugin.wasm").unwrap(); | |
let wasi = Wasi::new(&store, WasiCtx::new(std::env::args()).unwrap()); | |
let mut imports = Vec::new(); | |
for import in module.imports() { | |
if import.module() == "wasi_snapshot_preview1" { | |
if let Some(export) = wasi.get_export(import.name()) { | |
imports.push(Extern::from(export.clone())); | |
continue; | |
} | |
} | |
panic!( | |
"couldn't find import for `{}::{}`", | |
import.module(), | |
import.name() | |
); | |
} | |
let inst = Instance::new(&module, &imports).unwrap(); | |
let mut plugin = PluginInstance::new(inst); | |
let s = api::CommonStruct { a: 5, b: 6, c: "Hello World!".to_string() }; | |
let buf = api::bincode::serialize(&s).unwrap(); | |
let (ptr, len) = plugin.write_object_to_memory(&buf[..]); | |
plugin.call_function("plugin_test_fn", &[Val::I32(ptr), Val::I32(len)]).unwrap(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Use our own allocator to create a buffer that the host can use to transfer | |
/// data without overwriting data from our plugin | |
#[no_mangle] | |
pub extern "C" fn alloc_runtime_buffer(size: usize) -> *mut u8 { | |
let mut buf = vec![0; size]; | |
let ptr = buf.as_mut_ptr(); | |
//TODO: docs on forget() say that the pointer might not be valid indefinitely. | |
// maybe a boxed buffer and Box::into_raw should be used instead of a Vec. | |
std::mem::forget(buf); | |
ptr | |
} | |
#[no_mangle] | |
pub extern "C" fn plugin_test_fn(buf: &[u8]) { | |
let s = api::bincode::deserialize::<api::CommonStruct>(buf).unwrap(); | |
let a = 32; | |
let b = 3.0; | |
let c = "foobar"; | |
println!("Random stack values {} {} {}", a, b, c); | |
println!("Hello from wasm! {:?}", s); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment