]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/step.rs
db90714d0e6231d7b747fa142f8c6e21d112ac00
[rust.git] / src / librustc_mir / interpret / step.rs
1 //! This module contains the `EvalContext` methods for executing a single step of the interpreter.
2 //!
3 //! The main entry point is the `step` method.
4
5 use rustc::mir;
6
7 use rustc::mir::interpret::EvalResult;
8 use super::{EvalContext, Machine};
9
10 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
11     pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
12         /// The number of steps between loop detector snapshots.
13         /// Should be a power of two for performance reasons.
14         const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
15
16         {
17             let steps = &mut self.steps_since_detector_enabled;
18
19             *steps += 1;
20             if *steps < 0 {
21                 return Ok(());
22             }
23
24             *steps %= DETECTOR_SNAPSHOT_PERIOD;
25             if *steps != 0 {
26                 return Ok(());
27             }
28         }
29
30         if self.loop_detector.is_empty() {
31             // First run of the loop detector
32
33             // FIXME(#49980): make this warning a lint
34             self.tcx.sess.span_warn(self.frame().span,
35                 "Constant evaluating a complex constant, this might take some time");
36         }
37
38         self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
39     }
40
41     /// Returns true as long as there are more things to do.
42     pub fn step(&mut self) -> EvalResult<'tcx, bool> {
43         if self.stack.is_empty() {
44             return Ok(false);
45         }
46
47         let block = self.frame().block;
48         let stmt_id = self.frame().stmt;
49         let mir = self.mir();
50         let basic_block = &mir.basic_blocks()[block];
51
52         let old_frames = self.cur_frame();
53
54         if let Some(stmt) = basic_block.statements.get(stmt_id) {
55             assert_eq!(old_frames, self.cur_frame());
56             self.statement(stmt)?;
57             return Ok(true);
58         }
59
60         self.inc_step_counter_and_detect_loops()?;
61
62         let terminator = basic_block.terminator();
63         assert_eq!(old_frames, self.cur_frame());
64         self.terminator(terminator)?;
65         Ok(true)
66     }
67
68     fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
69         trace!("{:?}", stmt);
70
71         use rustc::mir::StatementKind::*;
72
73         // Some statements (e.g. box) push new stack frames.  We have to record the stack frame number
74         // *before* executing the statement.
75         let frame_idx = self.cur_frame();
76         self.tcx.span = stmt.source_info.span;
77         self.memory.tcx.span = stmt.source_info.span;
78
79         match stmt.kind {
80             Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
81
82             SetDiscriminant {
83                 ref place,
84                 variant_index,
85             } => {
86                 let dest = self.eval_place(place)?;
87                 let dest_ty = self.place_ty(place);
88                 self.write_discriminant_value(dest_ty, dest, variant_index)?;
89             }
90
91             // Mark locals as alive
92             StorageLive(local) => {
93                 let old_val = self.frame_mut().storage_live(local);
94                 self.deallocate_local(old_val)?;
95             }
96
97             // Mark locals as dead
98             StorageDead(local) => {
99                 let old_val = self.frame_mut().storage_dead(local);
100                 self.deallocate_local(old_val)?;
101             }
102
103             // No dynamic semantics attached to `ReadForMatch`; MIR
104             // interpreter is solely intended for borrowck'ed code.
105             ReadForMatch(..) => {}
106
107             // Validity checks.
108             Validate(op, ref places) => {
109                 for operand in places {
110                     M::validation_op(self, op, operand)?;
111                 }
112             }
113             EndRegion(ce) => {
114                 M::end_region(self, Some(ce))?;
115             }
116
117             UserAssertTy(..) => {}
118
119             // Defined to do nothing. These are added by optimization passes, to avoid changing the
120             // size of MIR constantly.
121             Nop => {}
122
123             InlineAsm { .. } => return err!(InlineAsm),
124         }
125
126         self.stack[frame_idx].stmt += 1;
127         Ok(())
128     }
129
130     fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
131         trace!("{:?}", terminator.kind);
132         self.tcx.span = terminator.source_info.span;
133         self.memory.tcx.span = terminator.source_info.span;
134         self.eval_terminator(terminator)?;
135         if !self.stack.is_empty() {
136             trace!("// {:?}", self.frame().block);
137         }
138         Ok(())
139     }
140 }