]> git.lizzy.rs Git - rust.git/blob - src/interpreter/stepper.rs
remove a debug message that snuck into the commit
[rust.git] / src / interpreter / stepper.rs
1 use super::{
2     FnEvalContext,
3     CachedMir,
4     TerminatorTarget,
5     ConstantId,
6 };
7 use error::EvalResult;
8 use rustc::mir::repr as mir;
9 use rustc::ty::{self, subst};
10 use rustc::mir::visit::Visitor;
11 use syntax::codemap::Span;
12 use memory::Pointer;
13 use std::rc::Rc;
14
15 pub enum Event {
16     Assignment,
17     Terminator,
18     Done,
19 }
20
21 pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
22     fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
23     block: mir::BasicBlock,
24     // a stack of statement positions
25     stmt: Vec<usize>,
26     mir: CachedMir<'mir, 'tcx>,
27     process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
28     // a stack of constants
29     constants: Vec<Vec<(ConstantId, Span)>>,
30 }
31
32 impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
33     pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
34         let mut stepper = Stepper {
35             block: fncx.frame().next_block,
36             mir: fncx.mir(),
37             fncx: fncx,
38             stmt: vec![0],
39             process: Self::dummy,
40             constants: Vec::new(),
41         };
42         stepper.extract_constants();
43         stepper
44     }
45
46     fn dummy(&mut self) -> EvalResult<()> { Ok(()) }
47
48     fn statement(&mut self) -> EvalResult<()> {
49         let block_data = self.mir.basic_block_data(self.block);
50         let stmt = &block_data.statements[*self.stmt.last().unwrap()];
51         let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
52         let result = self.fncx.eval_assignment(lvalue, rvalue);
53         self.fncx.maybe_report(stmt.span, result)?;
54         *self.stmt.last_mut().unwrap() += 1;
55         Ok(())
56     }
57
58     fn terminator(&mut self) -> EvalResult<()> {
59         *self.stmt.last_mut().unwrap() = 0;
60         let term = {
61             let block_data = self.mir.basic_block_data(self.block);
62             let terminator = block_data.terminator();
63             let result = self.fncx.eval_terminator(terminator);
64             self.fncx.maybe_report(terminator.span, result)?
65         };
66         match term {
67             TerminatorTarget::Block(block) => {
68                 self.block = block;
69             },
70             TerminatorTarget::Return => {
71                 self.fncx.pop_stack_frame();
72                 self.fncx.name_stack.pop();
73                 self.stmt.pop();
74                 assert!(self.constants.last().unwrap().is_empty());
75                 self.constants.pop();
76                 if !self.fncx.stack.is_empty() {
77                     self.block = self.fncx.frame().next_block;
78                     self.mir = self.fncx.mir();
79                 }
80             },
81             TerminatorTarget::Call => {
82                 self.block = self.fncx.frame().next_block;
83                 self.mir = self.fncx.mir();
84                 self.stmt.push(0);
85                 self.extract_constants();
86             },
87         }
88         Ok(())
89     }
90
91     fn alloc(&mut self, ty: ty::FnOutput<'tcx>) -> Pointer {
92         match ty {
93             ty::FnConverging(ty) => {
94                 let size = self.fncx.type_size(ty);
95                 self.fncx.memory.allocate(size)
96             }
97             ty::FnDiverging => panic!("there's no such thing as an unreachable static"),
98         }
99     }
100
101     pub fn step(&mut self) -> EvalResult<Event> {
102         (self.process)(self)?;
103
104         if self.fncx.stack.is_empty() {
105             // fuse the iterator
106             self.process = Self::dummy;
107             return Ok(Event::Done);
108         }
109
110         match self.constants.last_mut().unwrap().pop() {
111             Some((ConstantId::Promoted { index }, span)) => {
112                 trace!("adding promoted constant {}", index);
113                 let mir = self.mir.promoted[index].clone();
114                 let return_ptr = self.alloc(mir.return_ty);
115                 self.fncx.frame_mut().promoted.insert(index, return_ptr);
116                 let substs = self.fncx.substs();
117                 // FIXME: somehow encode that this is a promoted constant's frame
118                 let def_id = self.fncx.name_stack.last().unwrap().0;
119                 self.fncx.name_stack.push((def_id, substs, span));
120                 self.fncx.push_stack_frame(CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr));
121                 self.stmt.push(0);
122                 self.constants.push(Vec::new());
123                 self.block = self.fncx.frame().next_block;
124                 self.mir = self.fncx.mir();
125             },
126             Some((ConstantId::Static { def_id }, span)) => {
127                 trace!("adding static {:?}", def_id);
128                 let mir = self.fncx.load_mir(def_id);
129                 let return_ptr = self.alloc(mir.return_ty);
130                 self.fncx.gecx.statics.insert(def_id, return_ptr);
131                 let substs = self.fncx.tcx.mk_substs(subst::Substs::empty());
132                 self.fncx.name_stack.push((def_id, substs, span));
133                 self.fncx.push_stack_frame(mir, substs, Some(return_ptr));
134                 self.stmt.push(0);
135                 self.constants.push(Vec::new());
136                 self.block = self.fncx.frame().next_block;
137                 self.mir = self.fncx.mir();
138             },
139             None => {},
140         }
141
142         let basic_block = self.mir.basic_block_data(self.block);
143
144         if basic_block.statements.len() > *self.stmt.last().unwrap() {
145             self.process = Self::statement;
146             return Ok(Event::Assignment);
147         }
148
149         self.process = Self::terminator;
150         Ok(Event::Terminator)
151     }
152
153     /// returns the basic block index of the currently processed block
154     pub fn block(&self) -> mir::BasicBlock {
155         self.block
156     }
157
158     /// returns the statement that will be processed next
159     pub fn stmt(&self) -> &mir::Statement {
160         let block_data = self.mir.basic_block_data(self.block);
161         &block_data.statements[*self.stmt.last().unwrap()]
162     }
163
164     /// returns the terminator of the current block
165     pub fn term(&self) -> &mir::Terminator {
166         let block_data = self.mir.basic_block_data(self.block);
167         block_data.terminator()
168     }
169
170     fn extract_constants(&mut self) {
171         let mut extractor = ConstantExtractor {
172             constants: Vec::new(),
173         };
174         extractor.visit_mir(&self.mir);
175         self.constants.push(extractor.constants);
176     }
177 }
178
179 struct ConstantExtractor {
180     constants: Vec<(ConstantId, Span)>,
181 }
182
183 impl<'tcx> Visitor<'tcx> for ConstantExtractor {
184     fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
185         self.super_constant(constant);
186         match constant.literal {
187             // already computed by rustc
188             mir::Literal::Value { .. } => {}
189             mir::Literal::Item { .. } => {}, // FIXME: unimplemented
190             mir::Literal::Promoted { index } => {
191                 self.constants.push((ConstantId::Promoted { index: index }, constant.span));
192             }
193         }
194     }
195
196     fn visit_statement(&mut self, block: mir::BasicBlock, stmt: &mir::Statement<'tcx>) {
197         self.super_statement(block, stmt);
198         if let mir::StatementKind::Assign(mir::Lvalue::Static(def_id), _) = stmt.kind {
199             self.constants.push((ConstantId::Static { def_id: def_id }, stmt.span));
200         }
201     }
202 }