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