9 use rustc::mir::repr as mir;
10 use rustc::ty::subst::{self, Subst};
11 use rustc::hir::def_id::DefId;
12 use rustc::mir::visit::{Visitor, LvalueContext};
13 use syntax::codemap::Span;
23 pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
24 fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
25 mir: CachedMir<'mir, 'tcx>,
26 process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
29 impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
30 pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
38 fn dummy(&mut self) -> EvalResult<()> { Ok(()) }
40 fn statement(&mut self) -> EvalResult<()> {
41 let block_data = self.mir.basic_block_data(self.fncx.frame().next_block);
42 let stmt = &block_data.statements[self.fncx.frame().stmt];
43 let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
44 let result = self.fncx.eval_assignment(lvalue, rvalue);
45 self.fncx.maybe_report(stmt.span, result)?;
46 self.fncx.frame_mut().stmt += 1;
50 fn terminator(&mut self) -> EvalResult<()> {
51 // after a terminator we go to a new block
52 self.fncx.frame_mut().stmt = 0;
54 let block_data = self.mir.basic_block_data(self.fncx.frame().next_block);
55 let terminator = block_data.terminator();
56 let result = self.fncx.eval_terminator(terminator);
57 self.fncx.maybe_report(terminator.span, result)?
60 TerminatorTarget::Block => {},
61 TerminatorTarget::Return => {
62 assert!(self.fncx.frame().constants.is_empty());
63 self.fncx.pop_stack_frame();
64 if !self.fncx.stack.is_empty() {
65 self.mir = self.fncx.mir();
68 TerminatorTarget::Call => {
69 self.mir = self.fncx.mir();
75 fn constant(&mut self) -> EvalResult<()> {
76 let (cid, span, return_ptr, mir) = self.fncx.frame_mut().constants.pop().expect("state machine broken");
77 let def_id = cid.def_id();
78 let substs = cid.substs();
79 self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr));
80 self.mir = self.fncx.mir();
84 pub fn step(&mut self) -> EvalResult<Event> {
85 (self.process)(self)?;
87 if self.fncx.stack.is_empty() {
89 self.process = Self::dummy;
90 return Ok(Event::Done);
93 if !self.fncx.frame().constants.is_empty() {
94 self.process = Self::constant;
95 return Ok(Event::Constant);
98 let block = self.fncx.frame().next_block;
99 let stmt = self.fncx.frame().stmt;
100 let basic_block = self.mir.basic_block_data(block);
102 if let Some(ref stmt) = basic_block.statements.get(stmt) {
103 assert!(self.fncx.frame().constants.is_empty());
107 gecx: self.fncx.gecx,
108 frame: self.fncx.stack.last_mut().expect("stack empty"),
109 }.visit_statement(block, stmt);
110 if self.fncx.frame().constants.is_empty() {
111 self.process = Self::statement;
112 return Ok(Event::Assignment);
114 self.process = Self::constant;
115 return Ok(Event::Constant);
119 let terminator = basic_block.terminator();
120 assert!(self.fncx.frame().constants.is_empty());
122 span: terminator.span,
124 gecx: self.fncx.gecx,
125 frame: self.fncx.stack.last_mut().expect("stack empty"),
126 }.visit_terminator(block, terminator);
127 if self.fncx.frame().constants.is_empty() {
128 self.process = Self::terminator;
129 Ok(Event::Terminator)
131 self.process = Self::constant;
136 /// returns the statement that will be processed next
137 pub fn stmt(&self) -> &mir::Statement {
138 &self.fncx.basic_block().statements[self.fncx.frame().stmt]
141 /// returns the terminator of the current block
142 pub fn term(&self) -> &mir::Terminator {
143 self.fncx.basic_block().terminator()
146 pub fn block(&self) -> mir::BasicBlock {
147 self.fncx.frame().next_block
151 struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> {
153 mir: &'a CachedMir<'mir, 'tcx>,
154 frame: &'a mut Frame<'mir, 'tcx>,
155 gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
158 impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
159 fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) {
160 let cid = ConstantId::Static {
164 if self.gecx.statics.contains_key(&cid) {
167 let mir = self.gecx.load_mir(def_id);
168 let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
169 self.gecx.statics.insert(cid.clone(), ptr);
170 self.frame.constants.push((cid, span, ptr, mir));
174 impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> {
175 fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
176 self.super_constant(constant);
177 match constant.literal {
178 // already computed by rustc
179 mir::Literal::Value { .. } => {}
180 mir::Literal::Item { def_id, substs } => {
181 let item_ty = self.gecx.tcx.lookup_item_type(def_id).subst(self.gecx.tcx, substs);
182 if item_ty.ty.is_fn() {
185 self.static_item(def_id, substs, constant.span);
188 mir::Literal::Promoted { index } => {
189 let cid = ConstantId::Promoted {
190 def_id: self.frame.def_id,
191 substs: self.frame.substs,
194 if self.gecx.statics.contains_key(&cid) {
197 let mir = self.mir.promoted[index].clone();
198 let return_ty = mir.return_ty;
199 let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs()).expect("there's no such thing as an unreachable static");
200 let mir = CachedMir::Owned(Rc::new(mir));
201 self.gecx.statics.insert(cid.clone(), return_ptr);
202 self.frame.constants.push((cid, constant.span, return_ptr, mir));
207 fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) {
208 self.super_lvalue(lvalue, context);
209 if let mir::Lvalue::Static(def_id) = *lvalue {
210 let substs = self.gecx.tcx.mk_substs(subst::Substs::empty());
211 let span = self.span;
212 self.static_item(def_id, substs, span);