1 //! Evaluate an exported Wasm function using Wasmtime. 2 3 use crate::generators::{self, DiffValue, DiffValueType}; 4 use crate::oracles::dummy; 5 use crate::oracles::engine::DiffInstance; 6 use crate::oracles::{compile_module, engine::DiffEngine, StoreLimits}; 7 use anyhow::{Context, Error, Result}; 8 use wasmtime::{Extern, FuncType, Instance, Module, Store, Trap, Val}; 9 10 /// A wrapper for using Wasmtime as a [`DiffEngine`]. 11 pub struct WasmtimeEngine { 12 pub(crate) config: generators::Config, 13 } 14 15 impl WasmtimeEngine { 16 /// Merely store the configuration; the engine is actually constructed 17 /// later. Ideally the store and engine could be built here but 18 /// `compile_module` takes a [`generators::Config`]; TODO re-factor this if 19 /// that ever changes. 20 pub fn new(config: generators::Config) -> Result<Self> { 21 Ok(Self { config }) 22 } 23 } 24 25 impl DiffEngine for WasmtimeEngine { 26 fn name(&self) -> &'static str { 27 "wasmtime" 28 } 29 30 fn instantiate(&mut self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> { 31 let store = self.config.to_store(); 32 let module = compile_module(store.engine(), wasm, true, &self.config).unwrap(); 33 let instance = WasmtimeInstance::new(store, module)?; 34 Ok(Box::new(instance)) 35 } 36 37 fn assert_error_match(&self, trap: &Trap, err: Error) { 38 let trap2 = err.downcast::<Trap>().unwrap(); 39 assert_eq!( 40 trap.trap_code(), 41 trap2.trap_code(), 42 "{}\nis not equal to\n{}", 43 trap, 44 trap2 45 ); 46 } 47 } 48 49 /// A wrapper around a Wasmtime instance. 50 /// 51 /// The Wasmtime engine constructs a new store and compiles an instance of a 52 /// Wasm module. 53 pub struct WasmtimeInstance { 54 store: Store<StoreLimits>, 55 instance: Instance, 56 } 57 58 impl WasmtimeInstance { 59 /// Instantiate a new Wasmtime instance. 60 pub fn new(mut store: Store<StoreLimits>, module: Module) -> Result<Self> { 61 let instance = dummy::dummy_linker(&mut store, &module) 62 .and_then(|l| l.instantiate(&mut store, &module)) 63 .context("unable to instantiate module in wasmtime")?; 64 Ok(Self { store, instance }) 65 } 66 67 /// Retrieve the names and types of all exported functions in the instance. 68 /// 69 /// This is useful for evaluating each exported function with different 70 /// values. The [`DiffInstance`] trait asks for the function name and we 71 /// need to know the function signature in order to pass in the right 72 /// arguments. 73 pub fn exported_functions(&mut self) -> Vec<(String, FuncType)> { 74 let exported_functions = self 75 .instance 76 .exports(&mut self.store) 77 .map(|e| (e.name().to_owned(), e.into_func())) 78 .filter_map(|(n, f)| f.map(|f| (n, f))) 79 .collect::<Vec<_>>(); 80 exported_functions 81 .into_iter() 82 .map(|(n, f)| (n, f.ty(&self.store))) 83 .collect() 84 } 85 86 /// Returns the list of globals and their types exported from this instance. 87 pub fn exported_globals(&mut self) -> Vec<(String, DiffValueType)> { 88 let globals = self 89 .instance 90 .exports(&mut self.store) 91 .filter_map(|e| { 92 let name = e.name(); 93 e.into_global().map(|g| (name.to_string(), g)) 94 }) 95 .collect::<Vec<_>>(); 96 97 globals 98 .into_iter() 99 .map(|(name, global)| { 100 ( 101 name, 102 global.ty(&self.store).content().clone().try_into().unwrap(), 103 ) 104 }) 105 .collect() 106 } 107 108 /// Returns the list of exported memories and whether or not it's a shared 109 /// memory. 110 pub fn exported_memories(&mut self) -> Vec<(String, bool)> { 111 self.instance 112 .exports(&mut self.store) 113 .filter_map(|e| { 114 let name = e.name(); 115 match e.into_extern() { 116 Extern::Memory(_) => Some((name.to_string(), false)), 117 Extern::SharedMemory(_) => Some((name.to_string(), true)), 118 _ => None, 119 } 120 }) 121 .collect() 122 } 123 } 124 125 impl DiffInstance for WasmtimeInstance { 126 fn name(&self) -> &'static str { 127 "wasmtime" 128 } 129 130 fn evaluate( 131 &mut self, 132 function_name: &str, 133 arguments: &[DiffValue], 134 _results: &[DiffValueType], 135 ) -> Result<Option<Vec<DiffValue>>> { 136 let arguments: Vec<_> = arguments.iter().map(Val::from).collect(); 137 138 let function = self 139 .instance 140 .get_func(&mut self.store, function_name) 141 .expect("unable to access exported function"); 142 let ty = function.ty(&self.store); 143 let mut results = vec![Val::I32(0); ty.results().len()]; 144 function.call(&mut self.store, &arguments, &mut results)?; 145 146 let results = results.into_iter().map(Val::into).collect(); 147 Ok(Some(results)) 148 } 149 150 fn get_global(&mut self, name: &str, _ty: DiffValueType) -> Option<DiffValue> { 151 Some( 152 self.instance 153 .get_global(&mut self.store, name) 154 .unwrap() 155 .get(&mut self.store) 156 .into(), 157 ) 158 } 159 160 fn get_memory(&mut self, name: &str, shared: bool) -> Option<Vec<u8>> { 161 Some(if shared { 162 let data = self 163 .instance 164 .get_shared_memory(&mut self.store, name) 165 .unwrap() 166 .data(); 167 unsafe { (*data).to_vec() } 168 } else { 169 self.instance 170 .get_memory(&mut self.store, name) 171 .unwrap() 172 .data(&self.store) 173 .to_vec() 174 }) 175 } 176 } 177 178 impl From<&DiffValue> for Val { 179 fn from(v: &DiffValue) -> Self { 180 match *v { 181 DiffValue::I32(n) => Val::I32(n), 182 DiffValue::I64(n) => Val::I64(n), 183 DiffValue::F32(n) => Val::F32(n), 184 DiffValue::F64(n) => Val::F64(n), 185 DiffValue::V128(n) => Val::V128(n), 186 DiffValue::FuncRef { null } => { 187 assert!(null); 188 Val::FuncRef(None) 189 } 190 DiffValue::ExternRef { null } => { 191 assert!(null); 192 Val::ExternRef(None) 193 } 194 } 195 } 196 } 197 198 impl Into<DiffValue> for Val { 199 fn into(self) -> DiffValue { 200 match self { 201 Val::I32(n) => DiffValue::I32(n), 202 Val::I64(n) => DiffValue::I64(n), 203 Val::F32(n) => DiffValue::F32(n), 204 Val::F64(n) => DiffValue::F64(n), 205 Val::V128(n) => DiffValue::V128(n), 206 Val::FuncRef(f) => DiffValue::FuncRef { null: f.is_none() }, 207 Val::ExternRef(e) => DiffValue::ExternRef { null: e.is_none() }, 208 } 209 } 210 } 211 212 #[test] 213 fn smoke() { 214 crate::oracles::engine::smoke_test_engine(|config| WasmtimeEngine::new(config)) 215 } 216