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::Alias(..)
| &ValueDef::Placeholder(..)
| &ValueDef::Trace(..)
| &ValueDef::None => {}
}
}

View file

@ -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();
}
}
}

View file

@ -14,6 +14,25 @@ pub struct InterpContext {
memories: PerEntity<Memory, InterpMemory>,
tables: PerEntity<Table, InterpTable>,
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 {
@ -54,15 +73,11 @@ impl InterpContext {
memories,
tables,
globals,
trace_log: vec![],
}
}
pub fn call(
&mut self,
module: &Module<'_>,
func: Func,
args: &[ConstVal],
) -> Option<SmallVec<[ConstVal; 2]>> {
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::<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(
Operator::CallIndirect { table_index, .. },
@ -129,7 +148,11 @@ impl InterpContext {
.collect::<Vec<_>>();
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::<Vec<_>>();
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<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) {
return Some(ret);
return ret;
}
panic!("Unknown import: {} with args: {:?}", name, args);
}

View file

@ -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<SmallVec<[ConstVal; 2]>> {
pub fn call_wasi(mem: &mut InterpMemory, name: &str, args: &[ConstVal]) -> Option<InterpResult> {
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,
}

View file

@ -8,6 +8,7 @@ pub enum ValueDef {
PickOutput(Value, usize, Type),
Alias(Value),
Placeholder(Type),
Trace(usize, Vec<Value>),
#[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!(),
}
}