+use arena::TypedArena;
use rustc::middle::const_eval;
use rustc::middle::def_id::DefId;
use rustc::middle::subst::{self, Subst, Substs};
use rustc::mir::mir_map::MirMap;
use rustc::mir::repr as mir;
use rustc::util::nodemap::DefIdMap;
+use rustc_data_structures::fnv::FnvHashMap;
use std::cell::RefCell;
use std::iter;
use std::ops::Deref;
const TRACE_EXECUTION: bool = true;
-struct Interpreter<'a, 'tcx: 'a> {
+struct Interpreter<'a, 'tcx: 'a, 'arena> {
/// The results of the type checker, from rustc.
tcx: &'a TyCtxt<'tcx>,
/// A local cache from DefIds to Mir for non-crate-local items.
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
+ /// An arena allocator for type representations.
+ repr_arena: &'arena TypedArena<Repr>,
+
+ /// A cache for in-memory representations of types.
+ repr_cache: RefCell<FnvHashMap<ty::Ty<'tcx>, &'arena Repr>>,
+
/// The virtual memory system.
memory: Memory,
Return,
}
-impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
- fn new(tcx: &'a TyCtxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
+impl<'a, 'tcx: 'a, 'arena> Interpreter<'a, 'tcx, 'arena> {
+ fn new(tcx: &'a TyCtxt<'tcx>, mir_map: &'a MirMap<'tcx>, repr_arena: &'arena TypedArena<Repr>)
+ -> Self
+ {
Interpreter {
tcx: tcx,
mir_map: mir_map,
mir_cache: RefCell::new(DefIdMap()),
+ repr_arena: repr_arena,
+ repr_cache: RefCell::new(FnvHashMap()),
memory: Memory::new(),
stack: Vec::new(),
substs_stack: Vec::new(),
Switch { ref discr, ref targets, .. } => {
let adt_ptr = try!(self.eval_lvalue(discr));
let adt_repr = self.lvalue_repr(discr);
- let discr_size = match adt_repr {
+ let discr_size = match *adt_repr {
Repr::Aggregate { discr_size, .. } => discr_size,
_ => panic!("attmpted to switch on non-aggregate type"),
};
Adt(_, variant_idx, _) =>
self.assign_to_aggregate(dest, &dest_repr, variant_idx, operands),
- Vec => match dest_repr {
+ Vec => match *dest_repr {
Repr::Array { elem_size, length } => {
assert_eq!(length, operands.len());
for (i, operand) in operands.iter().enumerate() {
self.eval_operand_and_repr(op).map(|(p, _)| p)
}
- fn eval_operand_and_repr(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<(Pointer, Repr)> {
+ fn eval_operand_and_repr(&mut self, op: &mir::Operand<'tcx>)
+ -> EvalResult<(Pointer, &'arena Repr)>
+ {
use rustc::mir::repr::Operand::*;
match *op {
Consume(ref lvalue) => Ok((try!(self.eval_lvalue(lvalue)), self.lvalue_repr(lvalue))),
}
}
- fn lvalue_repr(&self, lvalue: &mir::Lvalue<'tcx>) -> Repr {
+ // TODO(tsion): Replace this inefficient hack with a wrapper like LvalueTy (e.g. LvalueRepr).
+ fn lvalue_repr(&self, lvalue: &mir::Lvalue<'tcx>) -> &'arena Repr {
use rustc::mir::tcx::LvalueTy;
match self.current_frame().mir.lvalue_ty(self.tcx, lvalue) {
LvalueTy::Ty { ty } => self.ty_to_repr(ty),
LvalueTy::Downcast { ref adt_def, substs, variant_index } => {
let field_tys = adt_def.variants[variant_index].fields.iter()
.map(|f| f.ty(self.tcx, substs));
- self.make_aggregate_repr(iter::once(field_tys))
+ self.repr_arena.alloc(self.make_aggregate_repr(iter::once(field_tys)))
}
}
}
let base_repr = self.lvalue_repr(&proj.base);
use rustc::mir::repr::ProjectionElem::*;
match proj.elem {
- Field(field, _) => match base_repr {
+ Field(field, _) => match *base_repr {
Repr::Aggregate { discr_size: 0, ref variants, .. } => {
let fields = &variants[0];
base_ptr.offset(fields[field.index()].offset as isize)
_ => panic!("field access on non-product type: {:?}", base_repr),
},
- Downcast(..) => match base_repr {
+ Downcast(..) => match *base_repr {
Repr::Aggregate { discr_size, .. } => base_ptr.offset(discr_size as isize),
_ => panic!("variant downcast on non-aggregate type: {:?}", base_repr),
},
}
// TODO(tsion): Cache these outputs.
- fn ty_to_repr(&self, ty: ty::Ty<'tcx>) -> Repr {
+ fn ty_to_repr(&self, ty: ty::Ty<'tcx>) -> &'arena Repr {
+ let ty = ty.subst(self.tcx, self.current_substs());
+
+ if let Some(repr) = self.repr_cache.borrow().get(ty) {
+ return repr;
+ }
+
use syntax::ast::{IntTy, UintTy};
- match ty.subst(self.tcx, self.current_substs()).sty {
+ let repr = match ty.sty {
ty::TyBool => Repr::Primitive { size: 1 },
ty::TyInt(IntTy::Is) => Repr::isize(),
ty::TyInt(IntTy::I8) => Repr::Primitive { size: 1 },
}
ref t => panic!("can't convert type to repr: {:?}", t),
- }
+ };
+
+ let repr_ref = self.repr_arena.alloc(repr);
+ self.repr_cache.borrow_mut().insert(ty, repr_ref);
+ repr_ref
}
fn current_frame(&self) -> &Frame<'a, 'tcx> {
println!("Interpreting: {}", item.name);
- let mut miri = Interpreter::new(tcx, mir_map);
+ let repr_arena = TypedArena::new();
+ let mut miri = Interpreter::new(tcx, mir_map, &repr_arena);
let return_ptr = match mir.return_ty {
ty::FnConverging(ty) => {
let size = miri.ty_to_repr(ty).size();