rust/src/interpreter/stepper.rs

167 lines
6.1 KiB
Rust
Raw Normal View History

2016-06-01 17:05:20 +02:00
use super::{
CachedMir,
ConstantId,
EvalContext,
ConstantKind,
2016-06-01 17:05:20 +02:00
};
use error::EvalResult;
use rustc::mir::repr as mir;
use rustc::ty::{subst, self};
2016-06-03 15:48:56 +02:00
use rustc::hir::def_id::DefId;
use rustc::mir::visit::{Visitor, LvalueContext};
use syntax::codemap::Span;
use std::rc::Rc;
2016-06-01 17:05:20 +02:00
pub(super) struct Stepper<'ecx, 'a: 'ecx, 'tcx: 'a>{
ecx: &'ecx mut EvalContext<'a, 'tcx>,
2016-06-01 17:05:20 +02:00
}
impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
pub(super) fn new(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> Self {
2016-06-03 15:48:56 +02:00
Stepper {
ecx: ecx,
2016-06-03 15:48:56 +02:00
}
2016-06-01 17:05:20 +02:00
}
2016-06-01 19:01:40 +02:00
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> {
trace!("{:?}", stmt);
2016-06-01 17:05:20 +02:00
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
self.ecx.eval_assignment(lvalue, rvalue)?;
self.ecx.frame_mut().stmt += 1;
2016-06-01 17:05:20 +02:00
Ok(())
}
2016-06-01 19:01:40 +02:00
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> {
// after a terminator we go to a new block
self.ecx.frame_mut().stmt = 0;
2016-06-09 16:08:34 +02:00
trace!("{:?}", terminator.kind);
self.ecx.eval_terminator(terminator)?;
if !self.ecx.stack.is_empty() {
trace!("// {:?}", self.ecx.frame().next_block);
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(super) fn step(&mut self) -> EvalResult<bool> {
if self.ecx.stack.is_empty() {
return Ok(false);
2016-06-03 15:48:56 +02:00
}
let block = self.ecx.frame().next_block;
let stmt = self.ecx.frame().stmt;
let mir = self.ecx.mir();
2016-06-08 10:17:26 +02:00
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) {
let current_stack = self.ecx.stack.len();
2016-06-03 15:48:56 +02:00
ConstantExtractor {
span: stmt.span,
substs: self.ecx.substs(),
def_id: self.ecx.frame().def_id,
ecx: self.ecx,
mir: &mir,
2016-06-03 16:51:51 +02:00
}.visit_statement(block, stmt);
if current_stack == self.ecx.stack.len() {
self.statement(stmt)?;
2016-06-03 15:48:56 +02:00
} else {
// ConstantExtractor added some new frames for statics/constants/promoteds
// self.step() can't be "done", so it can't return false
assert!(self.step()?);
2016-06-03 15:48:56 +02:00
}
return Ok(true);
2016-06-01 17:05:20 +02:00
}
2016-06-03 15:48:56 +02:00
let terminator = basic_block.terminator();
let current_stack = self.ecx.stack.len();
2016-06-03 15:48:56 +02:00
ConstantExtractor {
span: terminator.span,
substs: self.ecx.substs(),
def_id: self.ecx.frame().def_id,
ecx: self.ecx,
mir: &mir,
2016-06-03 16:51:51 +02:00
}.visit_terminator(block, terminator);
if current_stack == self.ecx.stack.len() {
self.terminator(terminator)?;
2016-06-03 15:48:56 +02:00
} else {
// ConstantExtractor added some new frames for statics/constants/promoteds
// self.step() can't be "done", so it can't return false
assert!(self.step()?);
2016-06-03 15:48:56 +02:00
}
Ok(true)
2016-06-01 17:05:20 +02:00
}
2016-06-03 15:48:56 +02:00
}
// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
2016-06-03 15:48:56 +02:00
span: Span,
ecx: &'a mut EvalContext<'b, 'tcx>,
mir: &'a mir::Mir<'tcx>,
def_id: DefId,
substs: &'tcx subst::Substs<'tcx>,
}
impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
2016-06-09 11:27:12 +02:00
fn global_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,
2016-06-08 12:35:15 +02:00
kind: ConstantKind::Global,
2016-06-03 15:48:56 +02:00
};
if self.ecx.statics.contains_key(&cid) {
2016-06-03 17:41:36 +02:00
return;
}
let mir = self.ecx.load_mir(def_id);
let ptr = self.ecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
self.ecx.statics.insert(cid.clone(), ptr);
self.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr));
2016-06-03 15:48:56 +02:00
}
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, '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 } => {
if let ty::TyFnDef(..) = constant.ty.sty {
// No need to do anything here, even if function pointers are implemented,
// because the type is the actual function, not the signature of the function.
// Thus we can simply create a zero sized allocation in `evaluate_operand`
2016-06-03 15:48:56 +02:00
} else {
2016-06-09 11:27:12 +02:00
self.global_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.ecx.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.ecx.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.ecx.statics.insert(cid.clone(), return_ptr);
self.ecx.push_stack_frame(self.def_id, constant.span, mir, self.substs, Some(return_ptr));
}
}
}
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.ecx.tcx.mk_substs(subst::Substs::empty());
2016-06-03 15:48:56 +02:00
let span = self.span;
2016-06-09 11:27:12 +02:00
self.global_item(def_id, substs, span);
}
}
2016-06-01 17:05:20 +02:00
}