1 //! This module contains the `EvalContext` methods for executing a single step of the interpreter.
3 //! The main entry point is the `step` method.
7 use rustc::mir::interpret::EvalResult;
8 use super::{EvalContext, Machine};
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;
17 let steps = &mut self.steps_since_detector_enabled;
24 *steps %= DETECTOR_SNAPSHOT_PERIOD;
30 if self.loop_detector.is_empty() {
31 // First run of the loop detector
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");
38 self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
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() {
47 let block = self.frame().block;
48 let stmt_id = self.frame().stmt;
50 let basic_block = &mir.basic_blocks()[block];
52 let old_frames = self.cur_frame();
54 if let Some(stmt) = basic_block.statements.get(stmt_id) {
55 assert_eq!(old_frames, self.cur_frame());
56 self.statement(stmt)?;
60 self.inc_step_counter_and_detect_loops()?;
62 let terminator = basic_block.terminator();
63 assert_eq!(old_frames, self.cur_frame());
64 self.terminator(terminator)?;
68 fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
71 use rustc::mir::StatementKind::*;
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;
80 Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
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)?;
91 // Mark locals as alive
92 StorageLive(local) => {
93 let old_val = self.frame_mut().storage_live(local);
94 self.deallocate_local(old_val)?;
97 // Mark locals as dead
98 StorageDead(local) => {
99 let old_val = self.frame_mut().storage_dead(local);
100 self.deallocate_local(old_val)?;
103 // No dynamic semantics attached to `ReadForMatch`; MIR
104 // interpreter is solely intended for borrowck'ed code.
105 ReadForMatch(..) => {}
108 Validate(op, ref places) => {
109 for operand in places {
110 M::validation_op(self, op, operand)?;
114 M::end_region(self, Some(ce))?;
117 UserAssertTy(..) => {}
119 // Defined to do nothing. These are added by optimization passes, to avoid changing the
120 // size of MIR constantly.
123 InlineAsm { .. } => return err!(InlineAsm),
126 self.stack[frame_idx].stmt += 1;
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);