From 8fec1a7aa776ed0f1373a1531b8665f4e35919f5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 16:01:53 +0200 Subject: [PATCH 01/12] merge FnEvalContext into GlobalEvalContext --- src/interpreter/mod.rs | 115 ++++++++++++------------------------- src/interpreter/stepper.rs | 51 ++++++++-------- 2 files changed, 63 insertions(+), 103 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 6c0d58f1c4..33e7d49bc6 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -9,7 +9,7 @@ use rustc::ty::subst::{self, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::DefIdMap; use std::cell::RefCell; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::rc::Rc; use std::{iter, mem}; use syntax::ast; @@ -39,26 +39,9 @@ struct GlobalEvalContext<'a, 'tcx: 'a> { /// Precomputed statics, constants and promoteds statics: HashMap, Pointer>, -} - -struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> { - gecx: &'a mut GlobalEvalContext<'b, 'tcx>, /// The virtual call stack. - stack: Vec>, -} - -impl<'a, 'b, 'mir, 'tcx> Deref for FnEvalContext<'a, 'b, 'mir, 'tcx> { - type Target = GlobalEvalContext<'b, 'tcx>; - fn deref(&self) -> &Self::Target { - self.gecx - } -} - -impl<'a, 'b, 'mir, 'tcx> DerefMut for FnEvalContext<'a, 'b, 'mir, 'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.gecx - } + stack: Vec>, } /// A stack frame. @@ -160,20 +143,19 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { .bit_width() .expect("Session::target::uint_type was usize")/8), statics: HashMap::new(), + stack: Vec::new(), } } - fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { + fn call(&mut self, mir: &'a mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { let substs = self.tcx.mk_substs(subst::Substs::empty()); let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs); - let mut nested_fecx = FnEvalContext::new(self); + self.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); - nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); + self.frame_mut().return_ptr = return_ptr; - nested_fecx.frame_mut().return_ptr = return_ptr; - - nested_fecx.run()?; + self.run()?; Ok(return_ptr) } @@ -349,15 +331,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { ty.layout(&infcx).unwrap() }) } -} - -impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { - fn new(gecx: &'a mut GlobalEvalContext<'b, 'tcx>) -> Self { - FnEvalContext { - gecx: gecx, - stack: Vec::new(), - } - } #[inline(never)] #[cold] @@ -399,7 +372,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(()) } - fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, + fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>, return_ptr: Option) { let arg_tys = mir.arg_decls.iter().map(|a| a.ty); @@ -425,7 +398,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { }); let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); self.memory.allocate(size) }).collect(); @@ -459,7 +432,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { SwitchInt { ref discr, ref values, ref targets, .. } => { let discr_ptr = self.eval_lvalue(discr)?.to_ptr(); let discr_size = self - .type_layout(self.lvalue_ty(discr)) + .type_layout(self.lvalue_ty(discr), self.substs()) .size(&self.tcx.data_layout) .bytes() as usize; let discr_val = self.memory.read_uint(discr_ptr, discr_size)?; @@ -512,7 +485,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let name = self.tcx.item_name(def_id).as_str(); match fn_ty.sig.0.output { ty::FnConverging(ty) => { - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); let ret = return_ptr.unwrap(); self.call_intrinsic(&name, substs, args, ret, size)? } @@ -523,7 +496,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Abi::C => { match fn_ty.sig.0.output { ty::FnConverging(ty) => { - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); self.call_c_abi(def_id, args, return_ptr.unwrap(), size)? } ty::FnDiverging => unimplemented!(), @@ -553,7 +526,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let last_arg = args.last().unwrap(); let last = self.eval_operand(last_arg)?; let last_ty = self.operand_ty(last_arg); - let last_layout = self.type_layout(last_ty); + let last_layout = self.type_layout(last_ty, self.substs()); match (&last_ty.sty, last_layout) { (&ty::TyTuple(fields), &Layout::Univariant { ref variant, .. }) => { @@ -638,7 +611,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { // Filling drop. // FIXME(solson): Trait objects (with no static size) probably get filled, too. - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); self.memory.drop_fill(ptr, size)?; Ok(()) @@ -646,7 +619,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult { use rustc::ty::layout::Layout::*; - let adt_layout = self.type_layout(adt_ty); + let adt_layout = self.type_layout(adt_ty, self.substs()); let discr_val = match *adt_layout { General { discr, .. } | CEnum { discr, .. } => { @@ -699,7 +672,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { // FIXME(solson): Handle different integer types correctly. "add_with_overflow" => { let ty = *substs.types.get(subst::FnSpace, 0); - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); let left = self.memory.read_int(args[0], size)?; let right = self.memory.read_int(args[1], size)?; let (n, overflowed) = unsafe { @@ -713,7 +686,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { "copy_nonoverlapping" => { let elem_ty = *substs.types.get(subst::FnSpace, 0); - let elem_size = self.type_size(elem_ty); + let elem_size = self.type_size(elem_ty, self.substs()); let src = self.memory.read_ptr(args[0])?; let dest = self.memory.read_ptr(args[1])?; let count = self.memory.read_isize(args[2])?; @@ -729,7 +702,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { "forget" => { let arg_ty = *substs.types.get(subst::FnSpace, 0); - let arg_size = self.type_size(arg_ty); + let arg_size = self.type_size(arg_ty, self.substs()); self.memory.drop_fill(args[0], arg_size)?; } @@ -748,7 +721,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { // FIXME(solson): Handle different integer types correctly. "mul_with_overflow" => { let ty = *substs.types.get(subst::FnSpace, 0); - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); let left = self.memory.read_int(args[0], size)?; let right = self.memory.read_int(args[1], size)?; let (n, overflowed) = unsafe { @@ -760,7 +733,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { "offset" => { let pointee_ty = *substs.types.get(subst::FnSpace, 0); - let pointee_size = self.type_size(pointee_ty) as isize; + let pointee_size = self.type_size(pointee_ty, self.substs()) as isize; let ptr_arg = args[0]; let offset = self.memory.read_isize(args[1])?; @@ -781,7 +754,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { // FIXME(solson): Handle different integer types correctly. Use primvals? "overflowing_sub" => { let ty = *substs.types.get(subst::FnSpace, 0); - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); let left = self.memory.read_int(args[0], size)?; let right = self.memory.read_int(args[1], size)?; let n = left.wrapping_sub(right); @@ -790,20 +763,20 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { "size_of" => { let ty = *substs.types.get(subst::FnSpace, 0); - let size = self.type_size(ty) as u64; + let size = self.type_size(ty, self.substs()) as u64; self.memory.write_uint(dest, size, dest_size)?; } "size_of_val" => { let ty = *substs.types.get(subst::FnSpace, 0); if self.type_is_sized(ty) { - let size = self.type_size(ty) as u64; + let size = self.type_size(ty, self.substs()) as u64; self.memory.write_uint(dest, size, dest_size)?; } else { match ty.sty { ty::TySlice(_) | ty::TyStr => { let elem_ty = ty.sequence_element_type(self.tcx); - let elem_size = self.type_size(elem_ty) as u64; + let elem_size = self.type_size(elem_ty, self.substs()) as u64; let ptr_size = self.memory.pointer_size as isize; let n = self.memory.read_usize(args[0].offset(ptr_size))?; self.memory.write_uint(dest, n * elem_size, dest_size)?; @@ -911,7 +884,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { { let dest = self.eval_lvalue(lvalue)?.to_ptr(); let dest_ty = self.lvalue_ty(lvalue); - let dest_layout = self.type_layout(dest_ty); + let dest_layout = self.type_layout(dest_ty, self.substs()); use rustc::mir::repr::Rvalue::*; match *rvalue { @@ -951,7 +924,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Array { .. } => { let elem_size = match dest_ty.sty { - ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64, + ty::TyArray(elem_ty, _) => self.type_size(elem_ty, self.substs()) as u64, _ => panic!("tried to assign {:?} to non-array type {:?}", kind, dest_ty), }; @@ -1029,7 +1002,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Repeat(ref operand, _) => { let (elem_size, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n), + ty::TyArray(elem_ty, n) => (self.type_size(elem_ty, self.substs()), n), _ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty), }; @@ -1070,7 +1043,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } Box(ty) => { - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); let ptr = self.memory.allocate(size); self.memory.write_ptr(dest, ptr)?; } @@ -1164,7 +1137,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult { - let layout = self.type_layout(ty); + let layout = self.type_layout(ty, self.substs()); use rustc::ty::layout::Layout::*; match *layout { @@ -1229,13 +1202,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { substs: substs, kind: ConstantKind::Global, }; - *self.gecx.statics.get(&cid).expect("static should have been cached (lvalue)") + *self.statics.get(&cid).expect("static should have been cached (lvalue)") }, Projection(ref proj) => { let base = self.eval_lvalue(&proj.base)?; let base_ty = self.lvalue_ty(&proj.base); - let base_layout = self.type_layout(base_ty); + let base_layout = self.type_layout(base_ty, self.substs()); use rustc::mir::repr::ProjectionElem::*; match proj.elem { @@ -1296,7 +1269,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Index(ref operand) => { let elem_size = match base_ty.sty { ty::TyArray(elem_ty, _) | - ty::TySlice(elem_ty) => self.type_size(elem_ty), + ty::TySlice(elem_ty) => self.type_size(elem_ty, self.substs()), _ => panic!("indexing expected an array or slice, got {:?}", base_ty), }; let n_ptr = self.eval_operand(operand)?; @@ -1313,19 +1286,15 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { - self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx)) + self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx), self.substs()) } fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> { - self.monomorphize(self.mir().operand_ty(self.tcx, operand)) - } - - fn monomorphize(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.gecx.monomorphize(ty, self.substs()) + self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs()) } fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> { - let size = self.type_size(ty); + let size = self.type_size(ty, self.substs()); self.memory.copy(src, dest, size)?; if self.type_needs_drop(ty) { self.memory.drop_fill(src, size)?; @@ -1333,14 +1302,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(()) } - fn type_size(&self, ty: Ty<'tcx>) -> usize { - self.gecx.type_size(ty, self.substs()) - } - - fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout { - self.gecx.type_layout(ty, self.substs()) - } - pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult { use syntax::ast::{IntTy, UintTy}; let val = match (self.memory.pointer_size, &ty.sty) { @@ -1380,7 +1341,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(val) } - fn frame(&self) -> &Frame<'mir, 'tcx> { + fn frame(&self) -> &Frame<'a, 'tcx> { self.stack.last().expect("no call frames exist") } @@ -1389,11 +1350,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { frame.mir.basic_block_data(frame.next_block) } - fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> { + fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> { self.stack.last_mut().expect("no call frames exist") } - fn mir(&self) -> CachedMir<'mir, 'tcx> { + fn mir(&self) -> CachedMir<'a, 'tcx> { self.frame().mir.clone() } diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index a113b8f98e..836df7a8bf 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -1,5 +1,4 @@ use super::{ - FnEvalContext, CachedMir, TerminatorTarget, ConstantId, @@ -15,18 +14,18 @@ use syntax::codemap::Span; use std::rc::Rc; use memory::Pointer; -pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ - fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, +pub struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ + gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>, // a cache of the constants to be computed before the next statement/terminator // this is an optimization, so we don't have to allocate a new vector for every statement - constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>, + constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'a, 'tcx>)>, } -impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> { - pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self { +impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { + pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { Stepper { - fncx: fncx, + gecx: gecx, constants: Vec::new(), } } @@ -34,48 +33,48 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { trace!("{:?}", stmt); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; - let result = self.fncx.eval_assignment(lvalue, rvalue); - self.fncx.maybe_report(result)?; - self.fncx.frame_mut().stmt += 1; + let result = self.gecx.eval_assignment(lvalue, rvalue); + self.gecx.maybe_report(result)?; + self.gecx.frame_mut().stmt += 1; Ok(()) } fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { // after a terminator we go to a new block - self.fncx.frame_mut().stmt = 0; + self.gecx.frame_mut().stmt = 0; let term = { trace!("{:?}", terminator.kind); - let result = self.fncx.eval_terminator(terminator); - self.fncx.maybe_report(result)? + let result = self.gecx.eval_terminator(terminator); + self.gecx.maybe_report(result)? }; match term { TerminatorTarget::Return => { - self.fncx.pop_stack_frame(); + self.gecx.pop_stack_frame(); }, TerminatorTarget::Block | - TerminatorTarget::Call => trace!("// {:?}", self.fncx.frame().next_block), + TerminatorTarget::Call => trace!("// {:?}", self.gecx.frame().next_block), } Ok(()) } // returns true as long as there are more things to do pub fn step(&mut self) -> EvalResult { - if self.fncx.stack.is_empty() { + if self.gecx.stack.is_empty() { return Ok(false); } - let block = self.fncx.frame().next_block; - let stmt = self.fncx.frame().stmt; - let mir = self.fncx.mir(); + let block = self.gecx.frame().next_block; + let stmt = self.gecx.frame().stmt; + let mir = self.gecx.mir(); let basic_block = mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { assert!(self.constants.is_empty()); ConstantExtractor { span: stmt.span, - substs: self.fncx.substs(), - def_id: self.fncx.frame().def_id, - gecx: self.fncx.gecx, + substs: self.gecx.substs(), + def_id: self.gecx.frame().def_id, + gecx: self.gecx, constants: &mut self.constants, mir: &mir, }.visit_statement(block, stmt); @@ -91,9 +90,9 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx assert!(self.constants.is_empty()); ConstantExtractor { span: terminator.span, - substs: self.fncx.substs(), - def_id: self.fncx.frame().def_id, - gecx: self.fncx.gecx, + substs: self.gecx.substs(), + def_id: self.gecx.frame().def_id, + gecx: self.gecx, constants: &mut self.constants, mir: &mir, }.visit_terminator(block, terminator); @@ -109,7 +108,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx assert!(!self.constants.is_empty()); for (cid, span, return_ptr, mir) in self.constants.drain(..) { trace!("queuing a constant"); - self.fncx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr)); + self.gecx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr)); } // self.step() can't be "done", so it can't return false assert!(self.step()?); From ba9e25b2eb932e87d02aedefae867f5f768a66cc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 16:08:34 +0200 Subject: [PATCH 02/12] No more terminators --- src/interpreter/mod.rs | 37 +++++++++---------------------------- src/interpreter/stepper.rs | 17 +++++------------ 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 33e7d49bc6..1e65bc0aea 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -99,18 +99,6 @@ enum CachedMir<'mir, 'tcx: 'mir> { Owned(Rc>) } -/// Represents the action to be taken in the main loop as a result of executing a terminator. -enum TerminatorTarget { - /// Make a local jump to the next block - Block, - - /// Start executing from the new current frame. (For function calls.) - Call, - - /// Stop executing the current frame and resume the previous frame. - Return, -} - #[derive(Clone, Debug, Eq, PartialEq, Hash)] /// Uniquely identifies a specific constant or static struct ConstantId<'tcx> { @@ -412,21 +400,19 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) - -> EvalResult { + -> EvalResult<()> { use rustc::mir::repr::TerminatorKind::*; - let target = match terminator.kind { - Return => TerminatorTarget::Return, + match terminator.kind { + Return => self.pop_stack_frame(), Goto { target } => { self.frame_mut().next_block = target; - TerminatorTarget::Block }, If { ref cond, targets: (then_target, else_target) } => { let cond_ptr = self.eval_operand(cond)?; let cond_val = self.memory.read_bool(cond_ptr)?; self.frame_mut().next_block = if cond_val { then_target } else { else_target }; - TerminatorTarget::Block } SwitchInt { ref discr, ref values, ref targets, .. } => { @@ -450,7 +436,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } self.frame_mut().next_block = target_block; - TerminatorTarget::Block } Switch { ref discr, ref targets, adt_def } => { @@ -463,7 +448,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { match matching { Some(i) => { self.frame_mut().next_block = targets[i]; - TerminatorTarget::Block }, None => return Err(EvalError::InvalidDiscriminant), } @@ -549,8 +533,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { let dest = self.frame().locals[i]; self.move_(src, dest, src_ty)?; } - - TerminatorTarget::Call } abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))), @@ -566,13 +548,12 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { let ty = self.lvalue_ty(value); self.drop(ptr, ty)?; self.frame_mut().next_block = target; - TerminatorTarget::Block } Resume => unimplemented!(), - }; + } - Ok(target) + Ok(()) } fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> { @@ -662,7 +643,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { args: &[mir::Operand<'tcx>], dest: Pointer, dest_size: usize - ) -> EvalResult { + ) -> EvalResult<()> { let args_res: EvalResult> = args.iter() .map(|arg| self.eval_operand(arg)) .collect(); @@ -799,7 +780,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - Ok(TerminatorTarget::Call) + Ok(()) } fn call_c_abi( @@ -808,7 +789,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { args: &[mir::Operand<'tcx>], dest: Pointer, dest_size: usize, - ) -> EvalResult { + ) -> EvalResult<()> { let name = self.tcx.item_name(def_id); let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -861,7 +842,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - Ok(TerminatorTarget::Call) + Ok(()) } fn assign_fields>( diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 836df7a8bf..38490bbc26 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -1,6 +1,5 @@ use super::{ CachedMir, - TerminatorTarget, ConstantId, GlobalEvalContext, ConstantKind, @@ -42,17 +41,11 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { // after a terminator we go to a new block self.gecx.frame_mut().stmt = 0; - let term = { - trace!("{:?}", terminator.kind); - let result = self.gecx.eval_terminator(terminator); - self.gecx.maybe_report(result)? - }; - match term { - TerminatorTarget::Return => { - self.gecx.pop_stack_frame(); - }, - TerminatorTarget::Block | - TerminatorTarget::Call => trace!("// {:?}", self.gecx.frame().next_block), + trace!("{:?}", terminator.kind); + let result = self.gecx.eval_terminator(terminator); + self.gecx.maybe_report(result)?; + if !self.gecx.stack.is_empty() { + trace!("// {:?}", self.gecx.frame().next_block); } Ok(()) } From fc935c10f86ec7414f6b7c9466c6a3b8cc4625ef Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 16:13:42 +0200 Subject: [PATCH 03/12] print errors in one central location --- src/interpreter/mod.rs | 14 ++------------ src/interpreter/stepper.rs | 6 ++---- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 1e65bc0aea..8ac86e3ad1 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { #[inline(never)] #[cold] - fn report(&self, e: &EvalError) { + fn report(&self, e: EvalError) { let stmt = self.frame().stmt; let block = self.basic_block(); let span = if stmt < block.statements.len() { @@ -347,13 +347,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { err.emit(); } - fn maybe_report(&self, r: EvalResult) -> EvalResult { - if let Err(ref e) = r { - self.report(e); - } - r - } - fn run(&mut self) -> EvalResult<()> { let mut stepper = stepper::Stepper::new(self); while stepper.step()? {} @@ -1435,10 +1428,7 @@ pub fn interpret_start_points<'a, 'tcx>( gecx.memory.dump(return_ptr.alloc_id); }, Ok(None) => warn!("diverging function returned"), - Err(_e) => { - // TODO(solson): Detect whether the error was already reported or not. - // tcx.sess.err(&e.to_string()); - } + Err(e) => gecx.report(e), } } } diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 38490bbc26..c73a46c844 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -32,8 +32,7 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { trace!("{:?}", stmt); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; - let result = self.gecx.eval_assignment(lvalue, rvalue); - self.gecx.maybe_report(result)?; + self.gecx.eval_assignment(lvalue, rvalue)?; self.gecx.frame_mut().stmt += 1; Ok(()) } @@ -42,8 +41,7 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { // after a terminator we go to a new block self.gecx.frame_mut().stmt = 0; trace!("{:?}", terminator.kind); - let result = self.gecx.eval_terminator(terminator); - self.gecx.maybe_report(result)?; + self.gecx.eval_terminator(terminator)?; if !self.gecx.stack.is_empty() { trace!("// {:?}", self.gecx.frame().next_block); } From 2dbd82d29667480600846ec62bb0782056330c0e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 16:49:40 +0200 Subject: [PATCH 04/12] inline the `call` method into `interpret_start_points` --- src/interpreter/mod.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8ac86e3ad1..e70fe5e93f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -135,18 +135,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } } - fn call(&mut self, mir: &'a mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { - let substs = self.tcx.mk_substs(subst::Substs::empty()); - let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs); - - self.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); - - self.frame_mut().return_ptr = return_ptr; - - self.run()?; - Ok(return_ptr) - } - fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { match output_ty { ty::FnConverging(ty) => { @@ -1423,12 +1411,18 @@ pub fn interpret_start_points<'a, 'tcx>( debug!("Interpreting: {}", item.name); let mut gecx = GlobalEvalContext::new(tcx, mir_map); - match gecx.call(mir, tcx.map.local_def_id(id)) { - Ok(Some(return_ptr)) => if log_enabled!(::log::LogLevel::Debug) { - gecx.memory.dump(return_ptr.alloc_id); + let substs = tcx.mk_substs(subst::Substs::empty()); + let return_ptr = gecx.alloc_ret_ptr(mir.return_ty, substs); + + gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); + + match (gecx.run(), return_ptr) { + (Ok(()), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { + gecx.memory.dump(ptr.alloc_id); }, - Ok(None) => warn!("diverging function returned"), - Err(e) => gecx.report(e), + (Ok(()), None) => warn!("diverging function returned"), + // FIXME: diverging functions can end up here in some future miri + (Err(e), _) => gecx.report(e), } } } From 336206cec24b9e4bc38445f490ee4d32c9c815a1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 17:23:58 +0200 Subject: [PATCH 05/12] the `type_size` method's `substs` argument allows computing the locals before pushing the stack frame --- src/interpreter/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index e70fe5e93f..a7a57a7960 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -353,11 +353,16 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { ::log_settings::settings().indentation += 1; + let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { + let size = self.type_size(ty, substs); + self.memory.allocate(size) + }).collect(); + self.stack.push(Frame { mir: mir.clone(), next_block: mir::START_BLOCK, return_ptr: return_ptr, - locals: Vec::new(), + locals: locals, var_offset: num_args, temp_offset: num_args + num_vars, span: span, @@ -365,13 +370,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { substs: substs, stmt: 0, }); - - let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { - let size = self.type_size(ty, self.substs()); - self.memory.allocate(size) - }).collect(); - - self.frame_mut().locals = locals; } fn pop_stack_frame(&mut self) { From 8c3a066d8d6fec4720c171130816c97ed209ce95 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 17:24:42 +0200 Subject: [PATCH 06/12] get rid of the constants cache in the stepper this is possible due to the removal of `FnEvalContext` --- src/interpreter/stepper.rs | 51 ++++++++++++++------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index c73a46c844..47ee9874ad 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -11,21 +11,15 @@ use rustc::hir::def_id::DefId; use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use std::rc::Rc; -use memory::Pointer; pub struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>, - - // a cache of the constants to be computed before the next statement/terminator - // this is an optimization, so we don't have to allocate a new vector for every statement - constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'a, 'tcx>)>, } impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { Stepper { gecx: gecx, - constants: Vec::new(), } } @@ -60,64 +54,57 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { let basic_block = mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { - assert!(self.constants.is_empty()); + let current_stack = self.gecx.stack.len(); ConstantExtractor { span: stmt.span, substs: self.gecx.substs(), def_id: self.gecx.frame().def_id, gecx: self.gecx, - constants: &mut self.constants, mir: &mir, }.visit_statement(block, stmt); - if self.constants.is_empty() { + if current_stack == self.gecx.stack.len() { self.statement(stmt)?; } else { - self.extract_constants()?; + // ConstantExtractor added some new frames for statics/constants/promoteds + // self.step() can't be "done", so it can't return false + assert!(self.step()?); } return Ok(true); } let terminator = basic_block.terminator(); - assert!(self.constants.is_empty()); + let current_stack = self.gecx.stack.len(); ConstantExtractor { span: terminator.span, substs: self.gecx.substs(), def_id: self.gecx.frame().def_id, gecx: self.gecx, - constants: &mut self.constants, mir: &mir, }.visit_terminator(block, terminator); - if self.constants.is_empty() { + if current_stack == self.gecx.stack.len() { self.terminator(terminator)?; } else { - self.extract_constants()?; + // ConstantExtractor added some new frames for statics/constants/promoteds + // self.step() can't be "done", so it can't return false + assert!(self.step()?); } Ok(true) } - - fn extract_constants(&mut self) -> EvalResult<()> { - assert!(!self.constants.is_empty()); - for (cid, span, return_ptr, mir) in self.constants.drain(..) { - trace!("queuing a constant"); - self.gecx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr)); - } - // self.step() can't be "done", so it can't return false - assert!(self.step()?); - Ok(()) - } } -struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { +// WARNING: make sure that any methods implemented on this type don't ever access gecx.stack +// this includes any method that might access the stack +// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame` +// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons +struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> { span: Span, - // FIXME: directly push the new stackframes instead of doing this intermediate caching - constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>, gecx: &'a mut GlobalEvalContext<'b, 'tcx>, mir: &'a mir::Mir<'tcx>, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, } -impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { +impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> { fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { let cid = ConstantId { def_id: def_id, @@ -130,11 +117,11 @@ impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { let mir = self.gecx.load_mir(def_id); let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static"); self.gecx.statics.insert(cid.clone(), ptr); - self.constants.push((cid, span, ptr, mir)); + self.gecx.push_stack_frame(def_id, span, mir, substs, Some(ptr)); } } -impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> { +impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) { self.super_constant(constant); match constant.literal { @@ -163,7 +150,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static"); let mir = CachedMir::Owned(Rc::new(mir)); self.gecx.statics.insert(cid.clone(), return_ptr); - self.constants.push((cid, constant.span, return_ptr, mir)); + self.gecx.push_stack_frame(self.def_id, constant.span, mir, self.substs, Some(return_ptr)); } } } From 3b804942fdcc8858644218a570e034062021c7a4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 12:34:15 +0200 Subject: [PATCH 07/12] simplify the stepper interface --- src/interpreter/mod.rs | 26 ++++++++++++++------------ src/interpreter/stepper.rs | 10 +++++++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a7a57a7960..2673f56090 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; mod stepper; -struct GlobalEvalContext<'a, 'tcx: 'a> { +pub struct GlobalEvalContext<'a, 'tcx: 'a> { /// The results of the type checker, from rustc. tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -335,12 +335,6 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { err.emit(); } - fn run(&mut self) -> EvalResult<()> { - let mut stepper = stepper::Stepper::new(self); - while stepper.step()? {} - Ok(()) - } - fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>, return_ptr: Option) { @@ -1414,14 +1408,22 @@ pub fn interpret_start_points<'a, 'tcx>( gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); - match (gecx.run(), return_ptr) { - (Ok(()), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { + loop { match (stepper::step(&mut gecx), return_ptr) { + (Ok(true), _) => {}, + (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { gecx.memory.dump(ptr.alloc_id); + break; + }, + (Ok(false), None) => { + warn!("diverging function returned"); + break; }, - (Ok(()), None) => warn!("diverging function returned"), // FIXME: diverging functions can end up here in some future miri - (Err(e), _) => gecx.report(e), - } + (Err(e), _) => { + gecx.report(e); + break; + }, + } } } } } diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 47ee9874ad..10145bdce2 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -12,12 +12,16 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use std::rc::Rc; -pub struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ +struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>, } +pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> EvalResult { + Stepper::new(gecx).step() +} + impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { - pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { + fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { Stepper { gecx: gecx, } @@ -43,7 +47,7 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { } // returns true as long as there are more things to do - pub fn step(&mut self) -> EvalResult { + fn step(&mut self) -> EvalResult { if self.gecx.stack.is_empty() { return Ok(false); } From b3c1713b89cacc7c86e7cf028f2206b309a6a152 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 13:01:51 +0200 Subject: [PATCH 08/12] expose a minimal API and use it in the binary --- src/bin/miri.rs | 85 +++++++++++++++++++++++++++- src/interpreter/mod.rs | 111 +++++++++---------------------------- src/interpreter/stepper.rs | 10 +--- src/lib.rs | 16 +++++- 4 files changed, 127 insertions(+), 95 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 34a8c1b2be..cec244a5c7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -7,11 +7,21 @@ extern crate rustc; extern crate rustc_driver; extern crate env_logger; extern crate log_settings; -extern crate log; +extern crate syntax; +#[macro_use] extern crate log; -use miri::interpreter; +use miri::{ + GlobalEvalContext, + CachedMir, + step, + EvalError, + Frame, +}; use rustc::session::Session; use rustc_driver::{driver, CompilerCalls}; +use rustc::ty::{TyCtxt, subst}; +use rustc::mir::mir_map::MirMap; +use rustc::hir::def_id::DefId; struct MiriCompilerCalls; @@ -25,13 +35,82 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { control.after_analysis.callback = Box::new(|state| { state.session.abort_if_errors(); - interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap()); + interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap()); }); control } } + + +fn interpret_start_points<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir_map: &MirMap<'tcx>, +) { + let initial_indentation = ::log_settings::settings().indentation; + for (&id, mir) in &mir_map.map { + for attr in tcx.map.attrs(id) { + use syntax::attr::AttrMetaMethods; + if attr.check_name("miri_run") { + let item = tcx.map.expect_item(id); + + ::log_settings::settings().indentation = initial_indentation; + + debug!("Interpreting: {}", item.name); + + let mut gecx = GlobalEvalContext::new(tcx, mir_map); + let substs = tcx.mk_substs(subst::Substs::empty()); + let return_ptr = gecx.alloc_ret_ptr(mir.return_ty, substs); + + gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); + + loop { match (step(&mut gecx), return_ptr) { + (Ok(true), _) => {}, + (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { + gecx.memory().dump(ptr.alloc_id); + break; + }, + (Ok(false), None) => { + warn!("diverging function returned"); + break; + }, + // FIXME: diverging functions can end up here in some future miri + (Err(e), _) => { + report(tcx, &gecx, e); + break; + }, + } } + } + } + } +} + +fn report(tcx: TyCtxt, gecx: &GlobalEvalContext, e: EvalError) { + let frame = gecx.stack().last().expect("stackframe was empty"); + let block = frame.mir.basic_block_data(frame.next_block); + let span = if frame.stmt < block.statements.len() { + block.statements[frame.stmt].span + } else { + block.terminator().span + }; + let mut err = tcx.sess.struct_span_err(span, &e.to_string()); + for &Frame { def_id, substs, span, .. } in gecx.stack().iter().rev() { + // FIXME(solson): Find a way to do this without this Display impl hack. + use rustc::util::ppaux; + use std::fmt; + struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>); + impl<'tcx> fmt::Display for Instance<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[], + |tcx| tcx.lookup_item_type(self.0).generics) + } + } + err.span_note(span, &format!("inside call to {}", Instance(def_id, substs))); + } + err.emit(); +} + #[miri_run] fn main() { init_logger(); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 2673f56090..3b08a0ff62 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -24,6 +24,10 @@ use std::collections::HashMap; mod stepper; +pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> EvalResult { + stepper::Stepper::new(gecx).step() +} + pub struct GlobalEvalContext<'a, 'tcx: 'a> { /// The results of the type checker, from rustc. tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -45,38 +49,38 @@ pub struct GlobalEvalContext<'a, 'tcx: 'a> { } /// A stack frame. -struct Frame<'a, 'tcx: 'a> { +pub struct Frame<'a, 'tcx: 'a> { /// The def_id of the current function - def_id: DefId, + pub def_id: DefId, /// The span of the call site - span: codemap::Span, + pub span: codemap::Span, /// type substitutions for the current function invocation - substs: &'tcx Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, /// The MIR for the function called on this frame. - mir: CachedMir<'a, 'tcx>, + pub mir: CachedMir<'a, 'tcx>, /// The block that is currently executed (or will be executed after the above call stacks return) - next_block: mir::BasicBlock, + pub next_block: mir::BasicBlock, /// A pointer for writing the return value of the current call if it's not a diverging call. - return_ptr: Option, + pub return_ptr: Option, /// The list of locals for the current function, stored in order as /// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset` /// and the temporaries at `self.temp_offset`. - locals: Vec, + pub locals: Vec, /// The offset of the first variable in `self.locals`. - var_offset: usize, + pub var_offset: usize, /// The offset of the first temporary in `self.locals`. - temp_offset: usize, + pub temp_offset: usize, /// The index of the currently evaluated statment - stmt: usize, + pub stmt: usize, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -94,7 +98,7 @@ enum LvalueExtra { } #[derive(Clone)] -enum CachedMir<'mir, 'tcx: 'mir> { +pub enum CachedMir<'mir, 'tcx: 'mir> { Ref(&'mir mir::Mir<'tcx>), Owned(Rc>) } @@ -120,7 +124,7 @@ enum ConstantKind { } impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { GlobalEvalContext { tcx: tcx, mir_map: mir_map, @@ -135,7 +139,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } } - fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { + pub fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { match output_ty { ty::FnConverging(ty) => { let size = self.type_size(ty, substs); @@ -145,6 +149,14 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } } + pub fn memory(&self) -> &Memory { + &self.memory + } + + pub fn stack(&self) -> &[Frame] { + &self.stack + } + // TODO(solson): Try making const_to_primval instead. fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult { use rustc::middle::const_val::ConstVal::*; @@ -308,34 +320,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { }) } - #[inline(never)] - #[cold] - fn report(&self, e: EvalError) { - let stmt = self.frame().stmt; - let block = self.basic_block(); - let span = if stmt < block.statements.len() { - block.statements[stmt].span - } else { - block.terminator().span - }; - let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() { - // FIXME(solson): Find a way to do this without this Display impl hack. - use rustc::util::ppaux; - use std::fmt; - struct Instance<'tcx>(DefId, &'tcx Substs<'tcx>); - impl<'tcx> fmt::Display for Instance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[], - |tcx| tcx.lookup_item_type(self.0).generics) - } - } - err.span_note(span, &format!("inside call to {}", Instance(def_id, substs))); - } - err.emit(); - } - - fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>, + pub fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>, return_ptr: Option) { let arg_tys = mir.arg_decls.iter().map(|a| a.ty); @@ -1387,48 +1372,6 @@ pub fn get_impl_method<'a, 'tcx>( } } -pub fn interpret_start_points<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir_map: &MirMap<'tcx>, -) { - let initial_indentation = ::log_settings::settings().indentation; - for (&id, mir) in &mir_map.map { - for attr in tcx.map.attrs(id) { - use syntax::attr::AttrMetaMethods; - if attr.check_name("miri_run") { - let item = tcx.map.expect_item(id); - - ::log_settings::settings().indentation = initial_indentation; - - debug!("Interpreting: {}", item.name); - - let mut gecx = GlobalEvalContext::new(tcx, mir_map); - let substs = tcx.mk_substs(subst::Substs::empty()); - let return_ptr = gecx.alloc_ret_ptr(mir.return_ty, substs); - - gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); - - loop { match (stepper::step(&mut gecx), return_ptr) { - (Ok(true), _) => {}, - (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { - gecx.memory.dump(ptr.alloc_id); - break; - }, - (Ok(false), None) => { - warn!("diverging function returned"); - break; - }, - // FIXME: diverging functions can end up here in some future miri - (Err(e), _) => { - gecx.report(e); - break; - }, - } } - } - } - } -} - // TODO(solson): Upstream these methods into rustc::ty::layout. trait IntegerExt { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 10145bdce2..942c913ccf 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -12,16 +12,12 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use std::rc::Rc; -struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ +pub(super) struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>, } -pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> EvalResult { - Stepper::new(gecx).step() -} - impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { - fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { + pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { Stepper { gecx: gecx, } @@ -47,7 +43,7 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { } // returns true as long as there are more things to do - fn step(&mut self) -> EvalResult { + pub(super) fn step(&mut self) -> EvalResult { if self.gecx.stack.is_empty() { return Ok(false); } diff --git a/src/lib.rs b/src/lib.rs index 4e06a3ce38..c5d74993dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,20 @@ extern crate log_settings; extern crate byteorder; mod error; -pub mod interpreter; +mod interpreter; mod memory; mod primval; + +pub use error::{ + EvalError, + EvalResult, +}; + +pub use interpreter::{ + GlobalEvalContext, + step, + Frame, + CachedMir, +}; + +pub use memory::Memory; From 6af821f20205e449ab022d04e669c8063b6b9cb4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 16:20:17 +0200 Subject: [PATCH 09/12] rename GlobalEvalContext to EvalContext --- src/bin/miri.rs | 6 +++--- src/interpreter/mod.rs | 8 ++++---- src/interpreter/stepper.rs | 8 ++++---- src/lib.rs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index cec244a5c7..f4e7ea0d7f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -11,7 +11,7 @@ extern crate syntax; #[macro_use] extern crate log; use miri::{ - GlobalEvalContext, + EvalContext, CachedMir, step, EvalError, @@ -59,7 +59,7 @@ fn interpret_start_points<'a, 'tcx>( debug!("Interpreting: {}", item.name); - let mut gecx = GlobalEvalContext::new(tcx, mir_map); + let mut gecx = EvalContext::new(tcx, mir_map); let substs = tcx.mk_substs(subst::Substs::empty()); let return_ptr = gecx.alloc_ret_ptr(mir.return_ty, substs); @@ -86,7 +86,7 @@ fn interpret_start_points<'a, 'tcx>( } } -fn report(tcx: TyCtxt, gecx: &GlobalEvalContext, e: EvalError) { +fn report(tcx: TyCtxt, gecx: &EvalContext, e: EvalError) { let frame = gecx.stack().last().expect("stackframe was empty"); let block = frame.mir.basic_block_data(frame.next_block); let span = if frame.stmt < block.statements.len() { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 3b08a0ff62..9fcb2da36b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -24,11 +24,11 @@ use std::collections::HashMap; mod stepper; -pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> EvalResult { +pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut EvalContext<'a, 'tcx>) -> EvalResult { stepper::Stepper::new(gecx).step() } -pub struct GlobalEvalContext<'a, 'tcx: 'a> { +pub struct EvalContext<'a, 'tcx: 'a> { /// The results of the type checker, from rustc. tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -123,9 +123,9 @@ enum ConstantKind { Global, } -impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { +impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { - GlobalEvalContext { + EvalContext { tcx: tcx, mir_map: mir_map, mir_cache: RefCell::new(DefIdMap()), diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 942c913ccf..7e1b328a4e 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -1,7 +1,7 @@ use super::{ CachedMir, ConstantId, - GlobalEvalContext, + EvalContext, ConstantKind, }; use error::EvalResult; @@ -13,11 +13,11 @@ use syntax::codemap::Span; use std::rc::Rc; pub(super) struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ - gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>, + gecx: &'fncx mut EvalContext<'a, 'tcx>, } impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { - pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self { + pub(super) fn new(gecx: &'fncx mut EvalContext<'a, 'tcx>) -> Self { Stepper { gecx: gecx, } @@ -98,7 +98,7 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { // The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> { span: Span, - gecx: &'a mut GlobalEvalContext<'b, 'tcx>, + gecx: &'a mut EvalContext<'b, 'tcx>, mir: &'a mir::Mir<'tcx>, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index c5d74993dc..c3369878f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ pub use error::{ }; pub use interpreter::{ - GlobalEvalContext, + EvalContext, step, Frame, CachedMir, From 4fa328ef5f69989078fa39f24e87d2c8368c5a80 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 16:20:25 +0200 Subject: [PATCH 10/12] remove unused method --- src/interpreter/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 9fcb2da36b..93140f58a9 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1284,11 +1284,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.stack.last().expect("no call frames exist") } - fn basic_block(&self) -> &mir::BasicBlockData<'tcx> { - let frame = self.frame(); - frame.mir.basic_block_data(frame.next_block) - } - fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> { self.stack.last_mut().expect("no call frames exist") } From 9c8f84caf774f5cb9e60a3c4bc14f6b514503c4d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 16:32:39 +0200 Subject: [PATCH 11/12] style nit --- src/bin/miri.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index f4e7ea0d7f..2948eb029e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -65,22 +65,24 @@ fn interpret_start_points<'a, 'tcx>( gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); - loop { match (step(&mut gecx), return_ptr) { - (Ok(true), _) => {}, - (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { - gecx.memory().dump(ptr.alloc_id); - break; - }, - (Ok(false), None) => { - warn!("diverging function returned"); - break; - }, - // FIXME: diverging functions can end up here in some future miri - (Err(e), _) => { - report(tcx, &gecx, e); - break; - }, - } } + loop { + match (step(&mut gecx), return_ptr) { + (Ok(true), _) => {}, + (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { + gecx.memory().dump(ptr.alloc_id); + break; + }, + (Ok(false), None) => { + warn!("diverging function returned"); + break; + }, + // FIXME: diverging functions can end up here in some future miri + (Err(e), _) => { + report(tcx, &gecx, e); + break; + }, + } + } } } } From cea2a8ae9eeadd02b3da38d819f95741449dd4e0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Jun 2016 16:56:04 +0200 Subject: [PATCH 12/12] adjust lifetimes and bindings to the GlobalEvalContext -> EvalContext rename --- src/bin/miri.rs | 18 +++++----- src/interpreter/mod.rs | 4 +-- src/interpreter/stepper.rs | 74 +++++++++++++++++++------------------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 2948eb029e..82702ae437 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -59,17 +59,17 @@ fn interpret_start_points<'a, 'tcx>( debug!("Interpreting: {}", item.name); - let mut gecx = EvalContext::new(tcx, mir_map); + let mut ecx = EvalContext::new(tcx, mir_map); let substs = tcx.mk_substs(subst::Substs::empty()); - let return_ptr = gecx.alloc_ret_ptr(mir.return_ty, substs); + let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs); - gecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); + ecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr); loop { - match (step(&mut gecx), return_ptr) { + match (step(&mut ecx), return_ptr) { (Ok(true), _) => {}, (Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) { - gecx.memory().dump(ptr.alloc_id); + ecx.memory().dump(ptr.alloc_id); break; }, (Ok(false), None) => { @@ -78,7 +78,7 @@ fn interpret_start_points<'a, 'tcx>( }, // FIXME: diverging functions can end up here in some future miri (Err(e), _) => { - report(tcx, &gecx, e); + report(tcx, &ecx, e); break; }, } @@ -88,8 +88,8 @@ fn interpret_start_points<'a, 'tcx>( } } -fn report(tcx: TyCtxt, gecx: &EvalContext, e: EvalError) { - let frame = gecx.stack().last().expect("stackframe was empty"); +fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) { + let frame = ecx.stack().last().expect("stackframe was empty"); let block = frame.mir.basic_block_data(frame.next_block); let span = if frame.stmt < block.statements.len() { block.statements[frame.stmt].span @@ -97,7 +97,7 @@ fn report(tcx: TyCtxt, gecx: &EvalContext, e: EvalError) { block.terminator().span }; let mut err = tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame { def_id, substs, span, .. } in gecx.stack().iter().rev() { + for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() { // FIXME(solson): Find a way to do this without this Display impl hack. use rustc::util::ppaux; use std::fmt; diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 93140f58a9..6831ab212f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -24,8 +24,8 @@ use std::collections::HashMap; mod stepper; -pub fn step<'fncx, 'a: 'fncx, 'tcx: 'a>(gecx: &'fncx mut EvalContext<'a, 'tcx>) -> EvalResult { - stepper::Stepper::new(gecx).step() +pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult { + stepper::Stepper::new(ecx).step() } pub struct EvalContext<'a, 'tcx: 'a> { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 7e1b328a4e..3e4816834a 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -12,57 +12,57 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use std::rc::Rc; -pub(super) struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{ - gecx: &'fncx mut EvalContext<'a, 'tcx>, +pub(super) struct Stepper<'ecx, 'a: 'ecx, 'tcx: 'a>{ + ecx: &'ecx mut EvalContext<'a, 'tcx>, } -impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { - pub(super) fn new(gecx: &'fncx mut EvalContext<'a, 'tcx>) -> Self { +impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> { + pub(super) fn new(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> Self { Stepper { - gecx: gecx, + ecx: ecx, } } fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { trace!("{:?}", stmt); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; - self.gecx.eval_assignment(lvalue, rvalue)?; - self.gecx.frame_mut().stmt += 1; + self.ecx.eval_assignment(lvalue, rvalue)?; + self.ecx.frame_mut().stmt += 1; Ok(()) } fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { // after a terminator we go to a new block - self.gecx.frame_mut().stmt = 0; + self.ecx.frame_mut().stmt = 0; trace!("{:?}", terminator.kind); - self.gecx.eval_terminator(terminator)?; - if !self.gecx.stack.is_empty() { - trace!("// {:?}", self.gecx.frame().next_block); + self.ecx.eval_terminator(terminator)?; + if !self.ecx.stack.is_empty() { + trace!("// {:?}", self.ecx.frame().next_block); } Ok(()) } // returns true as long as there are more things to do pub(super) fn step(&mut self) -> EvalResult { - if self.gecx.stack.is_empty() { + if self.ecx.stack.is_empty() { return Ok(false); } - let block = self.gecx.frame().next_block; - let stmt = self.gecx.frame().stmt; - let mir = self.gecx.mir(); + let block = self.ecx.frame().next_block; + let stmt = self.ecx.frame().stmt; + let mir = self.ecx.mir(); let basic_block = mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { - let current_stack = self.gecx.stack.len(); + let current_stack = self.ecx.stack.len(); ConstantExtractor { span: stmt.span, - substs: self.gecx.substs(), - def_id: self.gecx.frame().def_id, - gecx: self.gecx, + substs: self.ecx.substs(), + def_id: self.ecx.frame().def_id, + ecx: self.ecx, mir: &mir, }.visit_statement(block, stmt); - if current_stack == self.gecx.stack.len() { + if current_stack == self.ecx.stack.len() { self.statement(stmt)?; } else { // ConstantExtractor added some new frames for statics/constants/promoteds @@ -73,15 +73,15 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { } let terminator = basic_block.terminator(); - let current_stack = self.gecx.stack.len(); + let current_stack = self.ecx.stack.len(); ConstantExtractor { span: terminator.span, - substs: self.gecx.substs(), - def_id: self.gecx.frame().def_id, - gecx: self.gecx, + substs: self.ecx.substs(), + def_id: self.ecx.frame().def_id, + ecx: self.ecx, mir: &mir, }.visit_terminator(block, terminator); - if current_stack == self.gecx.stack.len() { + if current_stack == self.ecx.stack.len() { self.terminator(terminator)?; } else { // ConstantExtractor added some new frames for statics/constants/promoteds @@ -92,13 +92,13 @@ impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> { } } -// WARNING: make sure that any methods implemented on this type don't ever access gecx.stack +// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack // this includes any method that might access the stack // basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame` // The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> { span: Span, - gecx: &'a mut EvalContext<'b, 'tcx>, + ecx: &'a mut EvalContext<'b, 'tcx>, mir: &'a mir::Mir<'tcx>, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, @@ -111,13 +111,13 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> { substs: substs, kind: ConstantKind::Global, }; - if self.gecx.statics.contains_key(&cid) { + if self.ecx.statics.contains_key(&cid) { return; } - let mir = self.gecx.load_mir(def_id); - let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static"); - self.gecx.statics.insert(cid.clone(), ptr); - self.gecx.push_stack_frame(def_id, span, mir, substs, Some(ptr)); + let mir = self.ecx.load_mir(def_id); + let ptr = self.ecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static"); + self.ecx.statics.insert(cid.clone(), ptr); + self.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr)); } } @@ -142,15 +142,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { substs: self.substs, kind: ConstantKind::Promoted(index), }; - if self.gecx.statics.contains_key(&cid) { + if self.ecx.statics.contains_key(&cid) { return; } let mir = self.mir.promoted[index].clone(); let return_ty = mir.return_ty; - let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static"); + let return_ptr = self.ecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static"); let mir = CachedMir::Owned(Rc::new(mir)); - self.gecx.statics.insert(cid.clone(), return_ptr); - self.gecx.push_stack_frame(self.def_id, constant.span, mir, self.substs, Some(return_ptr)); + self.ecx.statics.insert(cid.clone(), return_ptr); + self.ecx.push_stack_frame(self.def_id, constant.span, mir, self.substs, Some(return_ptr)); } } } @@ -158,7 +158,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) { self.super_lvalue(lvalue, context); if let mir::Lvalue::Static(def_id) = *lvalue { - let substs = self.gecx.tcx.mk_substs(subst::Substs::empty()); + let substs = self.ecx.tcx.mk_substs(subst::Substs::empty()); let span = self.span; self.global_item(def_id, substs, span); }