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;
/// Precomputed statics, constants and promoteds
statics: HashMap<ConstantId<'tcx>, Pointer>,
-}
-
-struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> {
- gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
/// The virtual call stack.
- stack: Vec<Frame<'mir, 'tcx>>,
-}
-
-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<Frame<'a, 'tcx>>,
}
/// A stack frame.
.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<Option<Pointer>> {
+ fn call(&mut self, mir: &'a mir::Mir<'tcx>, def_id: DefId) -> EvalResult<Option<Pointer>> {
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)
}
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]
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<Pointer>)
{
let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
});
let locals: Vec<Pointer> = 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();
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)?;
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)?
}
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!(),
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, .. }) => {
// 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(())
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
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, .. } => {
// 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 {
"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])?;
"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)?;
}
// 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 {
"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])?;
// 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);
"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)?;
{
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 {
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),
};
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),
};
}
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)?;
}
}
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
- let layout = self.type_layout(ty);
+ let layout = self.type_layout(ty, self.substs());
use rustc::ty::layout::Layout::*;
match *layout {
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 {
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)?;
}
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)?;
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<PrimVal> {
use syntax::ast::{IntTy, UintTy};
let val = match (self.memory.pointer_size, &ty.sty) {
Ok(val)
}
- fn frame(&self) -> &Frame<'mir, 'tcx> {
+ fn frame(&self) -> &Frame<'a, 'tcx> {
self.stack.last().expect("no call frames exist")
}
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()
}
use super::{
- FnEvalContext,
CachedMir,
TerminatorTarget,
ConstantId,
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(),
}
}
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<bool> {
- 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);
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);
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()?);