1 //! Evaluate an exported Wasm function using Wasmtime. 2 3 use crate::generators::{self, DiffValue}; 4 use crate::oracles::engine::DiffInstance; 5 use crate::oracles::{compile_module, engine::DiffEngine, instantiate_with_dummy, StoreLimits}; 6 use anyhow::{Context, Result}; 7 use std::hash::Hash; 8 use std::slice; 9 use wasmtime::{AsContextMut, Extern, FuncType, Instance, Module, Store, Val}; 10 11 /// A wrapper for using Wasmtime as a [`DiffEngine`]. 12 pub struct WasmtimeEngine { 13 pub(crate) config: generators::Config, 14 } 15 16 impl WasmtimeEngine { 17 /// Merely store the configuration; the engine is actually constructed 18 /// later. Ideally the store and engine could be built here but 19 /// `compile_module` takes a [`generators::Config`]; TODO re-factor this if 20 /// that ever changes. 21 pub fn new(config: &generators::Config) -> Result<Box<Self>> { 22 Ok(Box::new(Self { 23 config: config.clone(), 24 })) 25 } 26 } 27 28 impl DiffEngine for WasmtimeEngine { 29 fn name(&self) -> &'static str { 30 "wasmtime" 31 } 32 33 fn instantiate(&self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> { 34 let store = self.config.to_store(); 35 let module = compile_module(store.engine(), wasm, true, &self.config).unwrap(); 36 let instance = WasmtimeInstance::new(store, module)?; 37 Ok(Box::new(instance)) 38 } 39 } 40 41 /// A wrapper around a Wasmtime instance. 42 /// 43 /// The Wasmtime engine constructs a new store and compiles an instance of a 44 /// Wasm module. 45 pub struct WasmtimeInstance { 46 store: Store<StoreLimits>, 47 instance: Instance, 48 } 49 50 impl WasmtimeInstance { 51 /// Instantiate a new Wasmtime instance. 52 pub fn new(mut store: Store<StoreLimits>, module: Module) -> Result<Self> { 53 let instance = instantiate_with_dummy(&mut store, &module) 54 .context("unable to instantiate module in wasmtime")?; 55 Ok(Self { store, instance }) 56 } 57 58 /// Retrieve the names and types of all exported functions in the instance. 59 /// 60 /// This is useful for evaluating each exported function with different 61 /// values. The [`DiffInstance`] trait asks for the function name and we 62 /// need to know the function signature in order to pass in the right 63 /// arguments. 64 pub fn exported_functions(&mut self) -> Vec<(String, FuncType)> { 65 let exported_functions = self 66 .instance 67 .exports(&mut self.store) 68 .map(|e| (e.name().to_owned(), e.into_func())) 69 .filter_map(|(n, f)| f.map(|f| (n, f))) 70 .collect::<Vec<_>>(); 71 exported_functions 72 .into_iter() 73 .map(|(n, f)| (n, f.ty(&self.store))) 74 .collect() 75 } 76 } 77 78 impl DiffInstance for WasmtimeInstance { 79 fn name(&self) -> &'static str { 80 "wasmtime" 81 } 82 83 fn evaluate(&mut self, function_name: &str, arguments: &[DiffValue]) -> Result<Vec<DiffValue>> { 84 let arguments: Vec<_> = arguments.iter().map(Val::from).collect(); 85 86 let function = self 87 .instance 88 .get_func(&mut self.store, function_name) 89 .expect("unable to access exported function"); 90 let ty = function.ty(&self.store); 91 let mut results = vec![Val::I32(0); ty.results().len()]; 92 function.call(&mut self.store, &arguments, &mut results)?; 93 94 let results = results.into_iter().map(Val::into).collect(); 95 Ok(results) 96 } 97 98 fn is_hashable(&self) -> bool { 99 true 100 } 101 102 fn hash(&mut self, state: &mut std::collections::hash_map::DefaultHasher) -> Result<()> { 103 let exports: Vec<_> = self 104 .instance 105 .exports(self.store.as_context_mut()) 106 .map(|e| e.into_extern()) 107 .collect(); 108 for e in exports { 109 match e { 110 Extern::Global(g) => { 111 let val: DiffValue = g.get(&mut self.store).into(); 112 val.hash(state) 113 } 114 Extern::Memory(m) => { 115 let data = m.data(&mut self.store); 116 data.hash(state) 117 } 118 Extern::SharedMemory(m) => { 119 let data = unsafe { slice::from_raw_parts(m.data() as *mut u8, m.data_size()) }; 120 data.hash(state) 121 } 122 Extern::Table(_) => { 123 // TODO: it's unclear whether it is worth it to iterate 124 // through the table and hash the values. 125 } 126 Extern::Func(_) => { 127 // Note: no need to hash exported functions. 128 } 129 } 130 } 131 Ok(()) 132 } 133 } 134 135 impl From<&DiffValue> for Val { 136 fn from(v: &DiffValue) -> Self { 137 match *v { 138 DiffValue::I32(n) => Val::I32(n), 139 DiffValue::I64(n) => Val::I64(n), 140 DiffValue::F32(n) => Val::F32(n), 141 DiffValue::F64(n) => Val::F64(n), 142 DiffValue::V128(n) => Val::V128(n), 143 } 144 } 145 } 146 147 impl Into<DiffValue> for Val { 148 fn into(self) -> DiffValue { 149 match self { 150 Val::I32(n) => DiffValue::I32(n), 151 Val::I64(n) => DiffValue::I64(n), 152 Val::F32(n) => DiffValue::F32(n), 153 Val::F64(n) => DiffValue::F64(n), 154 Val::V128(n) => DiffValue::V128(n), 155 Val::FuncRef(_) => unimplemented!(), 156 Val::ExternRef(_) => unimplemented!(), 157 } 158 } 159 } 160