diff --git a/src/backend/treeify.rs b/src/backend/treeify.rs index 22fd3a0..4693ce0 100644 --- a/src/backend/treeify.rs +++ b/src/backend/treeify.rs @@ -62,6 +62,7 @@ impl Trees { &ValueDef::BlockParam(..) | &ValueDef::Alias(..) | &ValueDef::Placeholder(..) + | &ValueDef::Trace(..) | &ValueDef::None => {} } } diff --git a/src/bin/waffle-util.rs b/src/bin/waffle-util.rs index b3260e1..3ce73c1 100644 --- a/src/bin/waffle-util.rs +++ b/src/bin/waffle-util.rs @@ -104,7 +104,7 @@ fn main() -> Result<()> { let mut ctx = InterpContext::new(&module); debug!("Calling start function"); if let Some(start) = module.start_func { - ctx.call(&module, start, &[]).unwrap(); + ctx.call(&module, start, &[]).ok().unwrap(); } // Find a function called `_start`, if any. if let Some(waffle::Export { @@ -113,7 +113,7 @@ fn main() -> Result<()> { }) = module.exports.iter().find(|e| &e.name == "_start") { debug!("Calling _start"); - ctx.call(&module, *func, &[]).unwrap(); + ctx.call(&module, *func, &[]).ok().unwrap(); } } } diff --git a/src/interp.rs b/src/interp.rs index c73d826..2133386 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -14,6 +14,25 @@ pub struct InterpContext { memories: PerEntity, tables: PerEntity, globals: PerEntity, + trace_log: Vec<(usize, Vec)>, +} + +type MultiVal = SmallVec<[ConstVal; 2]>; + +#[derive(Clone, Debug)] +pub enum InterpResult { + Ok(MultiVal), + Exit, + Trap, +} + +impl InterpResult { + pub fn ok(self) -> anyhow::Result { + match self { + InterpResult::Ok(vals) => Ok(vals), + other => anyhow::bail!("Bad InterpResult: {:?}", other), + } + } } impl InterpContext { @@ -54,15 +73,11 @@ impl InterpContext { memories, tables, globals, + trace_log: vec![], } } - pub fn call( - &mut self, - module: &Module<'_>, - func: Func, - args: &[ConstVal], - ) -> Option> { + pub fn call(&mut self, module: &Module<'_>, func: Func, args: &[ConstVal]) -> InterpResult { let body = match &module.funcs[func] { FuncDecl::Lazy(..) => panic!("Un-expanded function"), FuncDecl::Import(..) => { @@ -111,7 +126,11 @@ impl InterpContext { multivalue[0] }) .collect::>(); - self.call(module, function_index, &args[..])? + let result = self.call(module, function_index, &args[..]); + match result { + InterpResult::Ok(vals) => vals, + _ => return result, + } } &ValueDef::Operator( Operator::CallIndirect { table_index, .. }, @@ -129,7 +148,11 @@ impl InterpContext { .collect::>(); let idx = args.last().unwrap().as_u32().unwrap() as usize; let func = self.tables[table_index].elements[idx]; - self.call(module, func, &args[..args.len() - 1])? + let result = self.call(module, func, &args[..args.len() - 1]); + match result { + InterpResult::Ok(vals) => vals, + _ => return result, + } } &ValueDef::Operator(ref op, ref args, _) => { let args = args @@ -149,11 +172,28 @@ impl InterpContext { Some(result) => result, None => { log::trace!("const_eval failed on {:?} args {:?}", op, args); - return None; + return InterpResult::Trap; } }; smallvec![result] } + &ValueDef::Trace(id, ref args) => { + let args = args + .iter() + .map(|&arg| { + let arg = body.resolve_alias(arg); + let multivalue = frame + .values + .get(&arg) + .ok_or_else(|| format!("Unset SSA value: {}", arg)) + .unwrap(); + assert_eq!(multivalue.len(), 1); + multivalue[0] + }) + .collect::>(); + self.trace_log.push((id, args)); + smallvec![] + } &ValueDef::None | &ValueDef::Placeholder(..) | &ValueDef::BlockParam(..) => { unreachable!(); } @@ -165,7 +205,7 @@ impl InterpContext { match &body.blocks[frame.cur_block].terminator { &Terminator::None => unreachable!(), - &Terminator::Unreachable => return None, + &Terminator::Unreachable => return InterpResult::Trap, &Terminator::Br { ref target } => { frame.apply_target(body, target); } @@ -206,15 +246,15 @@ impl InterpContext { }) .collect(); log::trace!("returning from {}: {:?}", func, values); - return Some(values); + return InterpResult::Ok(values); } } } } - fn call_import(&mut self, name: &str, args: &[ConstVal]) -> Option> { + fn call_import(&mut self, name: &str, args: &[ConstVal]) -> InterpResult { if let Some(ret) = wasi::call_wasi(&mut self.memories[Memory::from(0)], name, args) { - return Some(ret); + return ret; } panic!("Unknown import: {} with args: {:?}", name, args); } diff --git a/src/interp/wasi.rs b/src/interp/wasi.rs index 749de8e..1d8ba6f 100644 --- a/src/interp/wasi.rs +++ b/src/interp/wasi.rs @@ -1,32 +1,28 @@ //! Very basic WASI implementation for interpreter: sufficient to let stdout work. -use crate::interp::{read_u32, write_u32, ConstVal, InterpMemory}; -use smallvec::{smallvec, SmallVec}; +use crate::interp::{read_u32, write_u32, ConstVal, InterpMemory, InterpResult}; +use smallvec::smallvec; -pub fn call_wasi( - mem: &mut InterpMemory, - name: &str, - args: &[ConstVal], -) -> Option> { +pub fn call_wasi(mem: &mut InterpMemory, name: &str, args: &[ConstVal]) -> Option { match name { "fd_prestat_get" => { - Some(smallvec![ConstVal::I32(8)]) // BADF + Some(InterpResult::Ok(smallvec![ConstVal::I32(8)])) // BADF } "args_sizes_get" => { let p_argc = args[0].as_u32().unwrap(); let p_argv_size = args[1].as_u32().unwrap(); write_u32(mem, p_argc, 0); write_u32(mem, p_argv_size, 0); - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } "environ_sizes_get" => { let p_environ_count = args[0].as_u32().unwrap(); let p_environ_buf_size = args[0].as_u32().unwrap(); write_u32(mem, p_environ_count, 0); write_u32(mem, p_environ_buf_size, 0); - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } - "args_get" => Some(smallvec![ConstVal::I32(0)]), + "args_get" => Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])), "fd_fdstat_get" => { let fd = args[0].as_u32().unwrap(); let p_fdstat_t = args[1].as_u32().unwrap(); @@ -35,7 +31,7 @@ pub fn call_wasi( write_u32(mem, p_fdstat_t + 4, 0); // flags = 0 write_u32(mem, p_fdstat_t + 8, 0x40); // rights_base = WRITE write_u32(mem, p_fdstat_t + 12, 0); // rights_inheriting = 0 - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } else { None } @@ -56,24 +52,24 @@ pub fn call_wasi( written += len; } write_u32(mem, p_nwritten, written as u32); - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } else { None } } "proc_exit" => { eprintln!("WASI exit: {:?}", args[0]); - None + Some(InterpResult::Exit) } "clock_time_get" => { let p_time = args[2].as_u32().unwrap(); write_u32(mem, p_time, 0); - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } "clock_res_get" => { let p_res = args[1].as_u32().unwrap(); write_u32(mem, p_res, 1); - Some(smallvec![ConstVal::I32(0)]) + Some(InterpResult::Ok(smallvec![ConstVal::I32(0)])) } _ => None, } diff --git a/src/ir/value.rs b/src/ir/value.rs index 0808f7e..0a88431 100644 --- a/src/ir/value.rs +++ b/src/ir/value.rs @@ -8,6 +8,7 @@ pub enum ValueDef { PickOutput(Value, usize, Type), Alias(Value), Placeholder(Type), + Trace(usize, Vec), #[default] None, } @@ -20,6 +21,7 @@ impl ValueDef { &ValueDef::Operator(_, _, ref tys) if tys.len() == 1 => Some(tys[0]), &ValueDef::PickOutput(_, _, ty) => Some(ty), &ValueDef::Placeholder(ty) => Some(ty), + &ValueDef::Trace(_, _) => None, _ => None, } } @@ -45,6 +47,11 @@ impl ValueDef { &ValueDef::PickOutput(from, ..) => f(from), &ValueDef::Alias(value) => f(value), &ValueDef::Placeholder(_) => {} + &ValueDef::Trace(_, ref args) => { + for &arg in args { + f(arg); + } + } &ValueDef::None => panic!(), } } @@ -60,6 +67,11 @@ impl ValueDef { &mut ValueDef::PickOutput(ref mut from, ..) => f(from), &mut ValueDef::Alias(ref mut value) => f(value), &mut ValueDef::Placeholder(_) => {} + &mut ValueDef::Trace(_, ref mut args) => { + for arg in args { + f(arg); + } + } &mut ValueDef::None => panic!(), } }