1
Fork 0

Handle recursive calls without recursing in miri.

This commit is contained in:
Scott Olson 2016-03-14 20:39:51 -06:00
parent 66eb109070
commit 7bac5963b9

View file

@ -67,6 +67,9 @@ struct Frame<'a, 'tcx: 'a> {
/// The MIR for the function called on this frame. /// The MIR for the function called on this frame.
mir: CachedMir<'a, 'tcx>, mir: CachedMir<'a, 'tcx>,
/// The block in the MIR this frame will execute once a fn call returns back to this frame.
next_block: mir::BasicBlock,
/// A pointer for writing the return value of the current call, if it's not a diverging call. /// A pointer for writing the return value of the current call, if it's not a diverging call.
return_ptr: Option<Pointer>, return_ptr: Option<Pointer>,
@ -113,7 +116,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
mir_cache: RefCell::new(DefIdMap()), mir_cache: RefCell::new(DefIdMap()),
memory: Memory::new(), memory: Memory::new(),
stack: Vec::new(), stack: Vec::new(),
substs_stack: vec![tcx.mk_substs(Substs::empty())], substs_stack: Vec::new(),
} }
} }
@ -143,6 +146,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
self.stack.push(Frame { self.stack.push(Frame {
mir: mir.clone(), mir: mir.clone(),
next_block: mir::START_BLOCK,
return_ptr: return_ptr, return_ptr: return_ptr,
locals: locals, locals: locals,
var_offset: num_args, var_offset: num_args,
@ -176,14 +180,14 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
} }
} }
fn call(&mut self, mir: CachedMir<'a, 'tcx>, args: &[mir::Operand<'tcx>], fn run(&mut self) -> EvalResult<()> {
return_ptr: Option<Pointer>) -> EvalResult<()> { 'outer: while !self.stack.is_empty() {
try!(self.push_stack_frame(mir.clone(), args, return_ptr)); let mut current_block = self.current_frame().next_block;
let mut current_block = mir::START_BLOCK;
loop { loop {
if TRACE_EXECUTION { println!("Entering block: {:?}", current_block); } if TRACE_EXECUTION { println!("Entering block: {:?}", current_block); }
let block_data = mir.basic_block_data(current_block); let current_mir = self.current_frame().mir.clone(); // Cloning a reference.
let block_data = current_mir.basic_block_data(current_block);
for stmt in &block_data.statements { for stmt in &block_data.statements {
if TRACE_EXECUTION { println!("{:?}", stmt); } if TRACE_EXECUTION { println!("{:?}", stmt); }
@ -233,25 +237,24 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
} }
Call { ref func, ref args, ref destination, .. } => { Call { ref func, ref args, ref destination, .. } => {
let ptr = match *destination { let mut return_ptr = None;
Some((ref lv, _)) => Some(try!(self.eval_lvalue(lv)).0), if let Some((ref lv, target)) = *destination {
None => None, self.current_frame_mut().next_block = target;
}; return_ptr = Some(try!(self.eval_lvalue(lv)).0)
}
let func_ty = self.current_frame().mir.operand_ty(self.tcx, func); let func_ty = self.current_frame().mir.operand_ty(self.tcx, func);
match func_ty.sty { match func_ty.sty {
ty::TyFnDef(def_id, substs, _) => { ty::TyFnDef(def_id, substs, _) => {
self.substs_stack.push(substs);
let mir = self.load_mir(def_id); let mir = self.load_mir(def_id);
try!(self.call(mir, args, ptr)); self.substs_stack.push(substs);
try!(self.push_stack_frame(mir, args, return_ptr));
continue 'outer;
} }
_ => panic!("can't handle callee of type {:?}", func_ty), _ => panic!("can't handle callee of type {:?}", func_ty),
} }
if let Some((_, target)) = *destination {
current_block = target;
}
} }
Drop { target, .. } => { Drop { target, .. } => {
@ -265,6 +268,8 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
self.pop_stack_frame(); self.pop_stack_frame();
self.substs_stack.pop(); self.substs_stack.pop();
}
Ok(()) Ok(())
} }
@ -454,7 +459,8 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
// TODO(tsion): Cache these outputs. // TODO(tsion): Cache these outputs.
fn ty_to_repr(&self, ty: ty::Ty<'tcx>) -> Repr { fn ty_to_repr(&self, ty: ty::Ty<'tcx>) -> Repr {
use syntax::ast::IntTy; use syntax::ast::IntTy;
let substs = self.substs_stack.last().unwrap(); let substs = self.substs_stack.last().map(|&s| s)
.unwrap_or_else(|| self.tcx.mk_substs(Substs::empty()));
match ty.subst(self.tcx, substs).sty { match ty.subst(self.tcx, substs).sty {
ty::TyBool => Repr::Bool, ty::TyBool => Repr::Bool,
@ -509,6 +515,10 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
fn current_frame(&self) -> &Frame<'a, 'tcx> { fn current_frame(&self) -> &Frame<'a, 'tcx> {
self.stack.last().expect("no call frames exist") self.stack.last().expect("no call frames exist")
} }
fn current_frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
self.stack.last_mut().expect("no call frames exist")
}
} }
pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>) { pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>) {
@ -528,7 +538,8 @@ pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>)
} }
ty::FnDiverging => None, ty::FnDiverging => None,
}; };
miri.call(CachedMir::Ref(mir), &[], return_ptr).unwrap(); miri.push_stack_frame(CachedMir::Ref(mir), &[], return_ptr).unwrap();
miri.run().unwrap();
if let Some(ret) = return_ptr { if let Some(ret) = return_ptr {
println!("Returned: {:?}\n", miri.memory.get(ret.alloc_id).unwrap()); println!("Returned: {:?}\n", miri.memory.get(ret.alloc_id).unwrap());