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