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