rust/src/interpreter/stepper.rs

202 lines
7.2 KiB
Rust
Raw Normal View History

2016-06-01 17:05:20 +02:00
use super::{
FnEvalContext,
CachedMir,
TerminatorTarget,
ConstantId,
2016-06-08 11:11:08 +02:00
GlobalEvalContext,
ConstantKind,
2016-06-01 17:05:20 +02:00
};
use error::EvalResult;
use rustc::mir::repr as mir;
2016-06-03 15:48:56 +02:00
use rustc::ty::subst::{self, Subst};
use rustc::hir::def_id::DefId;
use rustc::mir::visit::{Visitor, LvalueContext};
use syntax::codemap::Span;
use std::rc::Rc;
use memory::Pointer;
2016-06-01 17:05:20 +02:00
2016-06-08 11:34:56 +02:00
pub enum Event<'a, 'tcx: 'a> {
Block(mir::BasicBlock),
Return,
Call,
2016-06-03 15:48:56 +02:00
Constant,
2016-06-08 11:34:56 +02:00
Assignment(&'a mir::Statement<'tcx>),
Terminator(&'a mir::Terminator<'tcx>),
2016-06-01 17:05:20 +02:00
Done,
}
pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
// a cache of the constants to be computed before the next statement/terminator
// this is an optimization, so we don't have to allocate a new vector for every statement
constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
2016-06-01 17:05:20 +02:00
}
impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
2016-06-03 15:48:56 +02:00
Stepper {
2016-06-01 17:05:20 +02:00
fncx: fncx,
constants: Vec::new(),
2016-06-03 15:48:56 +02:00
}
2016-06-01 17:05:20 +02:00
}
2016-06-01 19:01:40 +02:00
2016-06-08 11:34:56 +02:00
fn statement<F: for<'f> FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> {
2016-06-08 10:17:26 +02:00
let mir = self.fncx.mir();
let block_data = mir.basic_block_data(self.fncx.frame().next_block);
let stmt = &block_data.statements[self.fncx.frame().stmt];
2016-06-08 11:34:56 +02:00
f(Event::Assignment(stmt));
2016-06-01 17:05:20 +02:00
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
let result = self.fncx.eval_assignment(lvalue, rvalue);
2016-06-08 11:11:08 +02:00
self.fncx.maybe_report(result)?;
self.fncx.frame_mut().stmt += 1;
2016-06-01 17:05:20 +02:00
Ok(())
}
2016-06-01 19:01:40 +02:00
2016-06-08 11:34:56 +02:00
fn terminator<F: for<'f> FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> {
// after a terminator we go to a new block
self.fncx.frame_mut().stmt = 0;
2016-06-01 17:05:20 +02:00
let term = {
2016-06-08 10:17:26 +02:00
let mir = self.fncx.mir();
let block_data = mir.basic_block_data(self.fncx.frame().next_block);
2016-06-01 17:05:20 +02:00
let terminator = block_data.terminator();
2016-06-08 11:34:56 +02:00
f(Event::Terminator(terminator));
2016-06-01 17:05:20 +02:00
let result = self.fncx.eval_terminator(terminator);
2016-06-08 11:11:08 +02:00
self.fncx.maybe_report(result)?
2016-06-01 17:05:20 +02:00
};
match term {
2016-06-08 11:34:56 +02:00
TerminatorTarget::Block => f(Event::Block(self.fncx.frame().next_block)),
2016-06-01 17:05:20 +02:00
TerminatorTarget::Return => {
2016-06-08 11:34:56 +02:00
f(Event::Return);
2016-06-01 17:05:20 +02:00
self.fncx.pop_stack_frame();
},
2016-06-08 11:34:56 +02:00
TerminatorTarget::Call => f(Event::Call),
2016-06-01 17:05:20 +02:00
}
Ok(())
}
2016-06-01 19:01:40 +02:00
2016-06-08 11:34:56 +02:00
// returns true as long as there are more things to do
pub fn step<F: for<'f> FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> {
2016-06-03 15:48:56 +02:00
if self.fncx.stack.is_empty() {
2016-06-08 11:34:56 +02:00
f(Event::Done);
return Ok(());
2016-06-03 15:48:56 +02:00
}
2016-06-03 16:51:51 +02:00
let block = self.fncx.frame().next_block;
let stmt = self.fncx.frame().stmt;
2016-06-08 10:17:26 +02:00
let mir = self.fncx.mir();
let basic_block = mir.basic_block_data(block);
2016-06-01 17:05:20 +02:00
if let Some(ref stmt) = basic_block.statements.get(stmt) {
assert!(self.constants.is_empty());
2016-06-03 15:48:56 +02:00
ConstantExtractor {
span: stmt.span,
substs: self.fncx.substs(),
def_id: self.fncx.frame().def_id,
gecx: self.fncx.gecx,
constants: &mut self.constants,
mir: &mir,
2016-06-03 16:51:51 +02:00
}.visit_statement(block, stmt);
if self.constants.is_empty() {
2016-06-08 11:34:56 +02:00
return self.statement(f);
2016-06-03 15:48:56 +02:00
} else {
2016-06-08 11:34:56 +02:00
return self.extract_constants(f);
2016-06-03 15:48:56 +02:00
}
2016-06-01 17:05:20 +02:00
}
2016-06-03 15:48:56 +02:00
let terminator = basic_block.terminator();
assert!(self.constants.is_empty());
2016-06-03 15:48:56 +02:00
ConstantExtractor {
span: terminator.span,
substs: self.fncx.substs(),
def_id: self.fncx.frame().def_id,
gecx: self.fncx.gecx,
constants: &mut self.constants,
mir: &mir,
2016-06-03 16:51:51 +02:00
}.visit_terminator(block, terminator);
if self.constants.is_empty() {
2016-06-08 11:34:56 +02:00
self.terminator(f)
2016-06-03 15:48:56 +02:00
} else {
2016-06-08 11:34:56 +02:00
self.extract_constants(f)
2016-06-03 15:48:56 +02:00
}
2016-06-01 17:05:20 +02:00
}
2016-06-08 11:34:56 +02:00
fn extract_constants<F: for<'f> FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> {
assert!(!self.constants.is_empty());
for (cid, span, return_ptr, mir) in self.constants.drain(..) {
2016-06-08 11:34:56 +02:00
f(Event::Constant);
self.fncx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr));
}
2016-06-08 11:34:56 +02:00
self.step(f)
}
2016-06-03 15:48:56 +02:00
}
struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> {
2016-06-03 15:48:56 +02:00
span: Span,
constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
mir: &'a mir::Mir<'tcx>,
def_id: DefId,
substs: &'tcx subst::Substs<'tcx>,
}
impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
2016-06-03 17:41:36 +02:00
fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) {
let cid = ConstantId {
2016-06-03 15:48:56 +02:00
def_id: def_id,
substs: substs,
kind: ConstantKind::Static,
2016-06-03 15:48:56 +02:00
};
if self.gecx.statics.contains_key(&cid) {
2016-06-03 17:41:36 +02:00
return;
}
let mir = self.gecx.load_mir(def_id);
let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
self.gecx.statics.insert(cid.clone(), ptr);
self.constants.push((cid, span, ptr, mir));
2016-06-03 15:48:56 +02:00
}
}
impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> {
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
self.super_constant(constant);
match constant.literal {
// already computed by rustc
mir::Literal::Value { .. } => {}
2016-06-03 15:48:56 +02:00
mir::Literal::Item { def_id, substs } => {
let item_ty = self.gecx.tcx.lookup_item_type(def_id).subst(self.gecx.tcx, substs);
2016-06-03 15:48:56 +02:00
if item_ty.ty.is_fn() {
// unimplemented
} else {
2016-06-03 17:41:36 +02:00
self.static_item(def_id, substs, constant.span);
2016-06-03 15:48:56 +02:00
}
},
mir::Literal::Promoted { index } => {
let cid = ConstantId {
def_id: self.def_id,
substs: self.substs,
kind: ConstantKind::Promoted(index),
2016-06-03 17:41:36 +02:00
};
if self.gecx.statics.contains_key(&cid) {
2016-06-03 15:48:56 +02:00
return;
}
let mir = self.mir.promoted[index].clone();
2016-06-03 15:48:56 +02:00
let return_ty = mir.return_ty;
let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static");
2016-06-03 15:48:56 +02:00
let mir = CachedMir::Owned(Rc::new(mir));
self.gecx.statics.insert(cid.clone(), return_ptr);
self.constants.push((cid, constant.span, return_ptr, mir));
}
}
}
2016-06-03 15:48:56 +02:00
fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) {
self.super_lvalue(lvalue, context);
if let mir::Lvalue::Static(def_id) = *lvalue {
let substs = self.gecx.tcx.mk_substs(subst::Substs::empty());
2016-06-03 15:48:56 +02:00
let span = self.span;
2016-06-03 17:41:36 +02:00
self.static_item(def_id, substs, span);
}
}
2016-06-01 17:05:20 +02:00
}