1 #![no_std] 2 3 #[macro_use] 4 extern crate alloc; 5 6 use alloc::string::ToString; 7 use anyhow::Result; 8 use wasmtime::{Engine, Instance, Linker, Module, Store}; 9 10 mod allocator; 11 mod panic; 12 13 /// Entrypoint of this embedding. 14 /// 15 /// This takes a number of parameters which are the precompiled module AOT 16 /// images that are run for each of the various tests below. The first parameter 17 /// is also where to put an error string, if any, if anything fails. 18 #[unsafe(no_mangle)] 19 pub unsafe extern "C" fn run( 20 error_buf: *mut u8, 21 error_size: usize, 22 smoke_module: *const u8, 23 smoke_size: usize, 24 simple_add_module: *const u8, 25 simple_add_size: usize, 26 simple_host_fn_module: *const u8, 27 simple_host_fn_size: usize, 28 ) -> usize { 29 let buf = core::slice::from_raw_parts_mut(error_buf, error_size); 30 let smoke = core::slice::from_raw_parts(smoke_module, smoke_size); 31 let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size); 32 let simple_host_fn = core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size); 33 match run_result(smoke, simple_add, simple_host_fn) { 34 Ok(()) => 0, 35 Err(e) => { 36 let msg = format!("{e:?}"); 37 let len = buf.len().min(msg.len()); 38 buf[..len].copy_from_slice(&msg.as_bytes()[..len]); 39 len 40 } 41 } 42 } 43 44 fn run_result( 45 smoke_module: &[u8], 46 simple_add_module: &[u8], 47 simple_host_fn_module: &[u8], 48 ) -> Result<()> { 49 smoke(smoke_module)?; 50 simple_add(simple_add_module)?; 51 simple_host_fn(simple_host_fn_module)?; 52 Ok(()) 53 } 54 55 fn smoke(module: &[u8]) -> Result<()> { 56 let engine = Engine::default(); 57 let module = match deserialize(&engine, module)? { 58 Some(module) => module, 59 None => return Ok(()), 60 }; 61 Instance::new(&mut Store::new(&engine, ()), &module, &[])?; 62 Ok(()) 63 } 64 65 fn simple_add(module: &[u8]) -> Result<()> { 66 let engine = Engine::default(); 67 let module = match deserialize(&engine, module)? { 68 Some(module) => module, 69 None => return Ok(()), 70 }; 71 let mut store = Store::new(&engine, ()); 72 let instance = Linker::new(&engine).instantiate(&mut store, &module)?; 73 let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?; 74 assert_eq!(func.call(&mut store, (2, 3))?, 5); 75 Ok(()) 76 } 77 78 fn simple_host_fn(module: &[u8]) -> Result<()> { 79 let engine = Engine::default(); 80 let module = match deserialize(&engine, module)? { 81 Some(module) => module, 82 None => return Ok(()), 83 }; 84 let mut linker = Linker::<()>::new(&engine); 85 linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?; 86 let mut store = Store::new(&engine, ()); 87 let instance = linker.instantiate(&mut store, &module)?; 88 let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?; 89 assert_eq!(func.call(&mut store, (2, 3, 4))?, 10); 90 Ok(()) 91 } 92 93 fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> { 94 match unsafe { Module::deserialize(engine, module) } { 95 Ok(module) => Ok(Some(module)), 96 Err(e) => { 97 // Currently if custom signals/virtual memory are disabled then this 98 // example is expected to fail to load since loading native code 99 // requires virtual memory. In the future this will go away as when 100 // signals-based-traps is disabled then that means that the 101 // interpreter should be used which should work here. 102 if !cfg!(feature = "custom") 103 && e.to_string() 104 .contains("requires virtual memory to be enabled") 105 { 106 Ok(None) 107 } else { 108 Err(e) 109 } 110 } 111 } 112 } 113