Some refactoring for tracepoints

This commit is contained in:
Chris Fallin 2023-02-24 12:48:28 -08:00
parent 5c48a0a3ea
commit 20ea31c9dd
5 changed files with 80 additions and 31 deletions

View file

@ -62,6 +62,7 @@ impl Trees {
&ValueDef::BlockParam(..) &ValueDef::BlockParam(..)
| &ValueDef::Alias(..) | &ValueDef::Alias(..)
| &ValueDef::Placeholder(..) | &ValueDef::Placeholder(..)
| &ValueDef::Trace(..)
| &ValueDef::None => {} | &ValueDef::None => {}
} }
} }

View file

@ -104,7 +104,7 @@ fn main() -> Result<()> {
let mut ctx = InterpContext::new(&module); let mut ctx = InterpContext::new(&module);
debug!("Calling start function"); debug!("Calling start function");
if let Some(start) = module.start_func { 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. // Find a function called `_start`, if any.
if let Some(waffle::Export { if let Some(waffle::Export {
@ -113,7 +113,7 @@ fn main() -> Result<()> {
}) = module.exports.iter().find(|e| &e.name == "_start") }) = module.exports.iter().find(|e| &e.name == "_start")
{ {
debug!("Calling _start"); debug!("Calling _start");
ctx.call(&module, *func, &[]).unwrap(); ctx.call(&module, *func, &[]).ok().unwrap();
} }
} }
} }

View file

@ -14,6 +14,25 @@ pub struct InterpContext {
memories: PerEntity<Memory, InterpMemory>, memories: PerEntity<Memory, InterpMemory>,
tables: PerEntity<Table, InterpTable>, tables: PerEntity<Table, InterpTable>,
globals: PerEntity<Global, ConstVal>, globals: PerEntity<Global, ConstVal>,
trace_log: Vec<(usize, Vec<ConstVal>)>,
}
type MultiVal = SmallVec<[ConstVal; 2]>;
#[derive(Clone, Debug)]
pub enum InterpResult {
Ok(MultiVal),
Exit,
Trap,
}
impl InterpResult {
pub fn ok(self) -> anyhow::Result<MultiVal> {
match self {
InterpResult::Ok(vals) => Ok(vals),
other => anyhow::bail!("Bad InterpResult: {:?}", other),
}
}
} }
impl InterpContext { impl InterpContext {
@ -54,15 +73,11 @@ impl InterpContext {
memories, memories,
tables, tables,
globals, globals,
trace_log: vec![],
} }
} }
pub fn call( pub fn call(&mut self, module: &Module<'_>, func: Func, args: &[ConstVal]) -> InterpResult {
&mut self,
module: &Module<'_>,
func: Func,
args: &[ConstVal],
) -> Option<SmallVec<[ConstVal; 2]>> {
let body = match &module.funcs[func] { let body = match &module.funcs[func] {
FuncDecl::Lazy(..) => panic!("Un-expanded function"), FuncDecl::Lazy(..) => panic!("Un-expanded function"),
FuncDecl::Import(..) => { FuncDecl::Import(..) => {
@ -111,7 +126,11 @@ impl InterpContext {
multivalue[0] multivalue[0]
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.call(module, function_index, &args[..])? let result = self.call(module, function_index, &args[..]);
match result {
InterpResult::Ok(vals) => vals,
_ => return result,
}
} }
&ValueDef::Operator( &ValueDef::Operator(
Operator::CallIndirect { table_index, .. }, Operator::CallIndirect { table_index, .. },
@ -129,7 +148,11 @@ impl InterpContext {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let idx = args.last().unwrap().as_u32().unwrap() as usize; let idx = args.last().unwrap().as_u32().unwrap() as usize;
let func = self.tables[table_index].elements[idx]; 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, _) => { &ValueDef::Operator(ref op, ref args, _) => {
let args = args let args = args
@ -149,11 +172,28 @@ impl InterpContext {
Some(result) => result, Some(result) => result,
None => { None => {
log::trace!("const_eval failed on {:?} args {:?}", op, args); log::trace!("const_eval failed on {:?} args {:?}", op, args);
return None; return InterpResult::Trap;
} }
}; };
smallvec![result] 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::<Vec<_>>();
self.trace_log.push((id, args));
smallvec![]
}
&ValueDef::None | &ValueDef::Placeholder(..) | &ValueDef::BlockParam(..) => { &ValueDef::None | &ValueDef::Placeholder(..) | &ValueDef::BlockParam(..) => {
unreachable!(); unreachable!();
} }
@ -165,7 +205,7 @@ impl InterpContext {
match &body.blocks[frame.cur_block].terminator { match &body.blocks[frame.cur_block].terminator {
&Terminator::None => unreachable!(), &Terminator::None => unreachable!(),
&Terminator::Unreachable => return None, &Terminator::Unreachable => return InterpResult::Trap,
&Terminator::Br { ref target } => { &Terminator::Br { ref target } => {
frame.apply_target(body, target); frame.apply_target(body, target);
} }
@ -206,15 +246,15 @@ impl InterpContext {
}) })
.collect(); .collect();
log::trace!("returning from {}: {:?}", func, values); log::trace!("returning from {}: {:?}", func, values);
return Some(values); return InterpResult::Ok(values);
} }
} }
} }
} }
fn call_import(&mut self, name: &str, args: &[ConstVal]) -> Option<SmallVec<[ConstVal; 2]>> { 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) { 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); panic!("Unknown import: {} with args: {:?}", name, args);
} }

View file

@ -1,32 +1,28 @@
//! Very basic WASI implementation for interpreter: sufficient to let stdout work. //! Very basic WASI implementation for interpreter: sufficient to let stdout work.
use crate::interp::{read_u32, write_u32, ConstVal, InterpMemory}; use crate::interp::{read_u32, write_u32, ConstVal, InterpMemory, InterpResult};
use smallvec::{smallvec, SmallVec}; use smallvec::smallvec;
pub fn call_wasi( pub fn call_wasi(mem: &mut InterpMemory, name: &str, args: &[ConstVal]) -> Option<InterpResult> {
mem: &mut InterpMemory,
name: &str,
args: &[ConstVal],
) -> Option<SmallVec<[ConstVal; 2]>> {
match name { match name {
"fd_prestat_get" => { "fd_prestat_get" => {
Some(smallvec![ConstVal::I32(8)]) // BADF Some(InterpResult::Ok(smallvec![ConstVal::I32(8)])) // BADF
} }
"args_sizes_get" => { "args_sizes_get" => {
let p_argc = args[0].as_u32().unwrap(); let p_argc = args[0].as_u32().unwrap();
let p_argv_size = args[1].as_u32().unwrap(); let p_argv_size = args[1].as_u32().unwrap();
write_u32(mem, p_argc, 0); write_u32(mem, p_argc, 0);
write_u32(mem, p_argv_size, 0); write_u32(mem, p_argv_size, 0);
Some(smallvec![ConstVal::I32(0)]) Some(InterpResult::Ok(smallvec![ConstVal::I32(0)]))
} }
"environ_sizes_get" => { "environ_sizes_get" => {
let p_environ_count = args[0].as_u32().unwrap(); let p_environ_count = args[0].as_u32().unwrap();
let p_environ_buf_size = 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_count, 0);
write_u32(mem, p_environ_buf_size, 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" => { "fd_fdstat_get" => {
let fd = args[0].as_u32().unwrap(); let fd = args[0].as_u32().unwrap();
let p_fdstat_t = args[1].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 + 4, 0); // flags = 0
write_u32(mem, p_fdstat_t + 8, 0x40); // rights_base = WRITE write_u32(mem, p_fdstat_t + 8, 0x40); // rights_base = WRITE
write_u32(mem, p_fdstat_t + 12, 0); // rights_inheriting = 0 write_u32(mem, p_fdstat_t + 12, 0); // rights_inheriting = 0
Some(smallvec![ConstVal::I32(0)]) Some(InterpResult::Ok(smallvec![ConstVal::I32(0)]))
} else { } else {
None None
} }
@ -56,24 +52,24 @@ pub fn call_wasi(
written += len; written += len;
} }
write_u32(mem, p_nwritten, written as u32); write_u32(mem, p_nwritten, written as u32);
Some(smallvec![ConstVal::I32(0)]) Some(InterpResult::Ok(smallvec![ConstVal::I32(0)]))
} else { } else {
None None
} }
} }
"proc_exit" => { "proc_exit" => {
eprintln!("WASI exit: {:?}", args[0]); eprintln!("WASI exit: {:?}", args[0]);
None Some(InterpResult::Exit)
} }
"clock_time_get" => { "clock_time_get" => {
let p_time = args[2].as_u32().unwrap(); let p_time = args[2].as_u32().unwrap();
write_u32(mem, p_time, 0); write_u32(mem, p_time, 0);
Some(smallvec![ConstVal::I32(0)]) Some(InterpResult::Ok(smallvec![ConstVal::I32(0)]))
} }
"clock_res_get" => { "clock_res_get" => {
let p_res = args[1].as_u32().unwrap(); let p_res = args[1].as_u32().unwrap();
write_u32(mem, p_res, 1); write_u32(mem, p_res, 1);
Some(smallvec![ConstVal::I32(0)]) Some(InterpResult::Ok(smallvec![ConstVal::I32(0)]))
} }
_ => None, _ => None,
} }

View file

@ -8,6 +8,7 @@ pub enum ValueDef {
PickOutput(Value, usize, Type), PickOutput(Value, usize, Type),
Alias(Value), Alias(Value),
Placeholder(Type), Placeholder(Type),
Trace(usize, Vec<Value>),
#[default] #[default]
None, None,
} }
@ -20,6 +21,7 @@ impl ValueDef {
&ValueDef::Operator(_, _, ref tys) if tys.len() == 1 => Some(tys[0]), &ValueDef::Operator(_, _, ref tys) if tys.len() == 1 => Some(tys[0]),
&ValueDef::PickOutput(_, _, ty) => Some(ty), &ValueDef::PickOutput(_, _, ty) => Some(ty),
&ValueDef::Placeholder(ty) => Some(ty), &ValueDef::Placeholder(ty) => Some(ty),
&ValueDef::Trace(_, _) => None,
_ => None, _ => None,
} }
} }
@ -45,6 +47,11 @@ impl ValueDef {
&ValueDef::PickOutput(from, ..) => f(from), &ValueDef::PickOutput(from, ..) => f(from),
&ValueDef::Alias(value) => f(value), &ValueDef::Alias(value) => f(value),
&ValueDef::Placeholder(_) => {} &ValueDef::Placeholder(_) => {}
&ValueDef::Trace(_, ref args) => {
for &arg in args {
f(arg);
}
}
&ValueDef::None => panic!(), &ValueDef::None => panic!(),
} }
} }
@ -60,6 +67,11 @@ impl ValueDef {
&mut ValueDef::PickOutput(ref mut from, ..) => f(from), &mut ValueDef::PickOutput(ref mut from, ..) => f(from),
&mut ValueDef::Alias(ref mut value) => f(value), &mut ValueDef::Alias(ref mut value) => f(value),
&mut ValueDef::Placeholder(_) => {} &mut ValueDef::Placeholder(_) => {}
&mut ValueDef::Trace(_, ref mut args) => {
for arg in args {
f(arg);
}
}
&mut ValueDef::None => panic!(), &mut ValueDef::None => panic!(),
} }
} }