]> git.lizzy.rs Git - rust.git/blob - src/interpreter/mod.rs
merge FnEvalContext into GlobalEvalContext
[rust.git] / src / interpreter / mod.rs
1 use rustc::middle::const_val;
2 use rustc::hir::def_id::DefId;
3 use rustc::mir::mir_map::MirMap;
4 use rustc::mir::repr as mir;
5 use rustc::traits::{self, ProjectionMode};
6 use rustc::ty::fold::TypeFoldable;
7 use rustc::ty::layout::{self, Layout, Size};
8 use rustc::ty::subst::{self, Subst, Substs};
9 use rustc::ty::{self, Ty, TyCtxt};
10 use rustc::util::nodemap::DefIdMap;
11 use std::cell::RefCell;
12 use std::ops::Deref;
13 use std::rc::Rc;
14 use std::{iter, mem};
15 use syntax::ast;
16 use syntax::attr;
17 use syntax::codemap::{self, DUMMY_SP};
18
19 use error::{EvalError, EvalResult};
20 use memory::{Memory, Pointer};
21 use primval::{self, PrimVal};
22
23 use std::collections::HashMap;
24
25 mod stepper;
26
27 struct GlobalEvalContext<'a, 'tcx: 'a> {
28     /// The results of the type checker, from rustc.
29     tcx: TyCtxt<'a, 'tcx, 'tcx>,
30
31     /// A mapping from NodeIds to Mir, from rustc. Only contains MIR for crate-local items.
32     mir_map: &'a MirMap<'tcx>,
33
34     /// A local cache from DefIds to Mir for non-crate-local items.
35     mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
36
37     /// The virtual memory system.
38     memory: Memory,
39
40     /// Precomputed statics, constants and promoteds
41     statics: HashMap<ConstantId<'tcx>, Pointer>,
42
43     /// The virtual call stack.
44     stack: Vec<Frame<'a, 'tcx>>,
45 }
46
47 /// A stack frame.
48 struct Frame<'a, 'tcx: 'a> {
49     /// The def_id of the current function
50     def_id: DefId,
51
52     /// The span of the call site
53     span: codemap::Span,
54
55     /// type substitutions for the current function invocation
56     substs: &'tcx Substs<'tcx>,
57
58     /// The MIR for the function called on this frame.
59     mir: CachedMir<'a, 'tcx>,
60
61     /// The block that is currently executed (or will be executed after the above call stacks return)
62     next_block: mir::BasicBlock,
63
64     /// A pointer for writing the return value of the current call if it's not a diverging call.
65     return_ptr: Option<Pointer>,
66
67     /// The list of locals for the current function, stored in order as
68     /// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
69     /// and the temporaries at `self.temp_offset`.
70     locals: Vec<Pointer>,
71
72     /// The offset of the first variable in `self.locals`.
73     var_offset: usize,
74
75     /// The offset of the first temporary in `self.locals`.
76     temp_offset: usize,
77
78     /// The index of the currently evaluated statment
79     stmt: usize,
80 }
81
82 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
83 struct Lvalue {
84     ptr: Pointer,
85     extra: LvalueExtra,
86 }
87
88 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
89 enum LvalueExtra {
90     None,
91     Length(u64),
92     // TODO(solson): Vtable(memory::AllocId),
93     DowncastVariant(usize),
94 }
95
96 #[derive(Clone)]
97 enum CachedMir<'mir, 'tcx: 'mir> {
98     Ref(&'mir mir::Mir<'tcx>),
99     Owned(Rc<mir::Mir<'tcx>>)
100 }
101
102 /// Represents the action to be taken in the main loop as a result of executing a terminator.
103 enum TerminatorTarget {
104     /// Make a local jump to the next block
105     Block,
106
107     /// Start executing from the new current frame. (For function calls.)
108     Call,
109
110     /// Stop executing the current frame and resume the previous frame.
111     Return,
112 }
113
114 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
115 /// Uniquely identifies a specific constant or static
116 struct ConstantId<'tcx> {
117     /// the def id of the constant/static or in case of promoteds, the def id of the function they belong to
118     def_id: DefId,
119     /// In case of statics and constants this is `Substs::empty()`, so only promoteds and associated
120     /// constants actually have something useful here. We could special case statics and constants,
121     /// but that would only require more branching when working with constants, and not bring any
122     /// real benefits.
123     substs: &'tcx Substs<'tcx>,
124     kind: ConstantKind,
125 }
126
127 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
128 enum ConstantKind {
129     Promoted(usize),
130     /// Statics, constants and associated constants
131     Global,
132 }
133
134 impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
135     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
136         GlobalEvalContext {
137             tcx: tcx,
138             mir_map: mir_map,
139             mir_cache: RefCell::new(DefIdMap()),
140             memory: Memory::new(tcx.sess
141                                    .target
142                                    .uint_type
143                                    .bit_width()
144                                    .expect("Session::target::uint_type was usize")/8),
145             statics: HashMap::new(),
146             stack: Vec::new(),
147         }
148     }
149
150     fn call(&mut self, mir: &'a mir::Mir<'tcx>, def_id: DefId) -> EvalResult<Option<Pointer>> {
151         let substs = self.tcx.mk_substs(subst::Substs::empty());
152         let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs);
153
154         self.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None);
155
156         self.frame_mut().return_ptr = return_ptr;
157
158         self.run()?;
159         Ok(return_ptr)
160     }
161
162     fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
163         match output_ty {
164             ty::FnConverging(ty) => {
165                 let size = self.type_size(ty, substs);
166                 Some(self.memory.allocate(size))
167             }
168             ty::FnDiverging => None,
169         }
170     }
171
172     // TODO(solson): Try making const_to_primval instead.
173     fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
174         use rustc::middle::const_val::ConstVal::*;
175         match *const_val {
176             Float(_f) => unimplemented!(),
177             Integral(int) => {
178                 // TODO(solson): Check int constant type.
179                 let ptr = self.memory.allocate(8);
180                 self.memory.write_uint(ptr, int.to_u64_unchecked(), 8)?;
181                 Ok(ptr)
182             }
183             Str(ref s) => {
184                 let psize = self.memory.pointer_size;
185                 let static_ptr = self.memory.allocate(s.len());
186                 let ptr = self.memory.allocate(psize * 2);
187                 self.memory.write_bytes(static_ptr, s.as_bytes())?;
188                 self.memory.write_ptr(ptr, static_ptr)?;
189                 self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?;
190                 Ok(ptr)
191             }
192             ByteStr(ref bs) => {
193                 let psize = self.memory.pointer_size;
194                 let static_ptr = self.memory.allocate(bs.len());
195                 let ptr = self.memory.allocate(psize);
196                 self.memory.write_bytes(static_ptr, bs)?;
197                 self.memory.write_ptr(ptr, static_ptr)?;
198                 Ok(ptr)
199             }
200             Bool(b) => {
201                 let ptr = self.memory.allocate(1);
202                 self.memory.write_bool(ptr, b)?;
203                 Ok(ptr)
204             }
205             Char(_c)          => unimplemented!(),
206             Struct(_node_id)  => unimplemented!(),
207             Tuple(_node_id)   => unimplemented!(),
208             Function(_def_id) => unimplemented!(),
209             Array(_, _)       => unimplemented!(),
210             Repeat(_, _)      => unimplemented!(),
211             Dummy             => unimplemented!(),
212         }
213     }
214
215     fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
216         self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
217     }
218
219     fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
220         ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
221     }
222
223     fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> {
224         // Do the initial selection for the obligation. This yields the shallow result we are
225         // looking for -- that is, what specific impl.
226         self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
227             let mut selcx = traits::SelectionContext::new(&infcx);
228
229             let obligation = traits::Obligation::new(
230                 traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
231                 trait_ref.to_poly_trait_predicate(),
232             );
233             let selection = selcx.select(&obligation).unwrap().unwrap();
234
235             // Currently, we use a fulfillment context to completely resolve all nested obligations.
236             // This is because they can inform the inference of the impl's type parameters.
237             let mut fulfill_cx = traits::FulfillmentContext::new();
238             let vtable = selection.map(|predicate| {
239                 fulfill_cx.register_predicate_obligation(&infcx, predicate);
240             });
241             infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable)
242         })
243     }
244
245     /// Trait method, which has to be resolved to an impl method.
246     pub fn trait_method(
247         &self,
248         def_id: DefId,
249         substs: &'tcx Substs<'tcx>
250     ) -> (DefId, &'tcx Substs<'tcx>) {
251         let method_item = self.tcx.impl_or_trait_item(def_id);
252         let trait_id = method_item.container().id();
253         let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id));
254         match self.fulfill_obligation(trait_ref) {
255             traits::VtableImpl(vtable_impl) => {
256                 let impl_did = vtable_impl.impl_def_id;
257                 let mname = self.tcx.item_name(def_id);
258                 // Create a concatenated set of substitutions which includes those from the impl
259                 // and those from the method:
260                 let impl_substs = vtable_impl.substs.with_method_from(substs);
261                 let substs = self.tcx.mk_substs(impl_substs);
262                 let mth = get_impl_method(self.tcx, impl_did, substs, mname);
263
264                 (mth.method.def_id, mth.substs)
265             }
266
267             traits::VtableClosure(vtable_closure) =>
268                 (vtable_closure.closure_def_id, vtable_closure.substs.func_substs),
269
270             traits::VtableFnPointer(_fn_ty) => {
271                 let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
272                 unimplemented!()
273                 // let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
274
275                 // let method_ty = def_ty(tcx, def_id, substs);
276                 // let fn_ptr_ty = match method_ty.sty {
277                 //     ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
278                 //     _ => unreachable!("expected fn item type, found {}",
279                 //                       method_ty)
280                 // };
281                 // Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
282             }
283
284             traits::VtableObject(ref _data) => {
285                 unimplemented!()
286                 // Callee {
287                 //     data: Virtual(traits::get_vtable_index_of_object_method(
288                 //                   tcx, data, def_id)),
289                 //                   ty: def_ty(tcx, def_id, substs)
290                 // }
291             }
292             vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable),
293         }
294     }
295
296     fn load_mir(&self, def_id: DefId) -> CachedMir<'a, 'tcx> {
297         match self.tcx.map.as_local_node_id(def_id) {
298             Some(node_id) => CachedMir::Ref(self.mir_map.map.get(&node_id).unwrap()),
299             None => {
300                 let mut mir_cache = self.mir_cache.borrow_mut();
301                 if let Some(mir) = mir_cache.get(&def_id) {
302                     return CachedMir::Owned(mir.clone());
303                 }
304
305                 let cs = &self.tcx.sess.cstore;
306                 let mir = cs.maybe_get_item_mir(self.tcx, def_id).unwrap_or_else(|| {
307                     panic!("no mir for {:?}", def_id);
308                 });
309                 let cached = Rc::new(mir);
310                 mir_cache.insert(def_id, cached.clone());
311                 CachedMir::Owned(cached)
312             }
313         }
314     }
315
316     fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
317         let substituted = ty.subst(self.tcx, substs);
318         self.tcx.normalize_associated_type(&substituted)
319     }
320
321     fn type_size(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
322         self.type_layout(ty, substs).size(&self.tcx.data_layout).bytes() as usize
323     }
324
325     fn type_layout(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout {
326         // TODO(solson): Is this inefficient? Needs investigation.
327         let ty = self.monomorphize(ty, substs);
328
329         self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
330             // TODO(solson): Report this error properly.
331             ty.layout(&infcx).unwrap()
332         })
333     }
334
335     #[inline(never)]
336     #[cold]
337     fn report(&self, e: &EvalError) {
338         let stmt = self.frame().stmt;
339         let block = self.basic_block();
340         let span = if stmt < block.statements.len() {
341             block.statements[stmt].span
342         } else {
343             block.terminator().span
344         };
345         let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
346         for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() {
347             // FIXME(solson): Find a way to do this without this Display impl hack.
348             use rustc::util::ppaux;
349             use std::fmt;
350             struct Instance<'tcx>(DefId, &'tcx Substs<'tcx>);
351             impl<'tcx> fmt::Display for Instance<'tcx> {
352                 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353                     ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
354                         |tcx| tcx.lookup_item_type(self.0).generics)
355                 }
356             }
357             err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
358         }
359         err.emit();
360     }
361
362     fn maybe_report<T>(&self, r: EvalResult<T>) -> EvalResult<T> {
363         if let Err(ref e) = r {
364             self.report(e);
365         }
366         r
367     }
368
369     fn run(&mut self) -> EvalResult<()> {
370         let mut stepper = stepper::Stepper::new(self);
371         while stepper.step()? {}
372         Ok(())
373     }
374
375     fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>,
376         return_ptr: Option<Pointer>)
377     {
378         let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
379         let var_tys = mir.var_decls.iter().map(|v| v.ty);
380         let temp_tys = mir.temp_decls.iter().map(|t| t.ty);
381
382         let num_args = mir.arg_decls.len();
383         let num_vars = mir.var_decls.len();
384
385         ::log_settings::settings().indentation += 1;
386
387         self.stack.push(Frame {
388             mir: mir.clone(),
389             next_block: mir::START_BLOCK,
390             return_ptr: return_ptr,
391             locals: Vec::new(),
392             var_offset: num_args,
393             temp_offset: num_args + num_vars,
394             span: span,
395             def_id: def_id,
396             substs: substs,
397             stmt: 0,
398         });
399
400         let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
401             let size = self.type_size(ty, self.substs());
402             self.memory.allocate(size)
403         }).collect();
404
405         self.frame_mut().locals = locals;
406     }
407
408     fn pop_stack_frame(&mut self) {
409         ::log_settings::settings().indentation -= 1;
410         let _frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
411         // TODO(solson): Deallocate local variables.
412     }
413
414     fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
415             -> EvalResult<TerminatorTarget> {
416         use rustc::mir::repr::TerminatorKind::*;
417         let target = match terminator.kind {
418             Return => TerminatorTarget::Return,
419
420             Goto { target } => {
421                 self.frame_mut().next_block = target;
422                 TerminatorTarget::Block
423             },
424
425             If { ref cond, targets: (then_target, else_target) } => {
426                 let cond_ptr = self.eval_operand(cond)?;
427                 let cond_val = self.memory.read_bool(cond_ptr)?;
428                 self.frame_mut().next_block = if cond_val { then_target } else { else_target };
429                 TerminatorTarget::Block
430             }
431
432             SwitchInt { ref discr, ref values, ref targets, .. } => {
433                 let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
434                 let discr_size = self
435                     .type_layout(self.lvalue_ty(discr), self.substs())
436                     .size(&self.tcx.data_layout)
437                     .bytes() as usize;
438                 let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
439
440                 // Branch to the `otherwise` case by default, if no match is found.
441                 let mut target_block = targets[targets.len() - 1];
442
443                 for (index, val_const) in values.iter().enumerate() {
444                     let ptr = self.const_to_ptr(val_const)?;
445                     let val = self.memory.read_uint(ptr, discr_size)?;
446                     if discr_val == val {
447                         target_block = targets[index];
448                         break;
449                     }
450                 }
451
452                 self.frame_mut().next_block = target_block;
453                 TerminatorTarget::Block
454             }
455
456             Switch { ref discr, ref targets, adt_def } => {
457                 let adt_ptr = self.eval_lvalue(discr)?.to_ptr();
458                 let adt_ty = self.lvalue_ty(discr);
459                 let discr_val = self.read_discriminant_value(adt_ptr, adt_ty)?;
460                 let matching = adt_def.variants.iter()
461                     .position(|v| discr_val == v.disr_val.to_u64_unchecked());
462
463                 match matching {
464                     Some(i) => {
465                         self.frame_mut().next_block = targets[i];
466                         TerminatorTarget::Block
467                     },
468                     None => return Err(EvalError::InvalidDiscriminant),
469                 }
470             }
471
472             Call { ref func, ref args, ref destination, .. } => {
473                 let mut return_ptr = None;
474                 if let Some((ref lv, target)) = *destination {
475                     self.frame_mut().next_block = target;
476                     return_ptr = Some(self.eval_lvalue(lv)?.to_ptr());
477                 }
478
479                 let func_ty = self.operand_ty(func);
480                 match func_ty.sty {
481                     ty::TyFnDef(def_id, substs, fn_ty) => {
482                         use syntax::abi::Abi;
483                         match fn_ty.abi {
484                             Abi::RustIntrinsic => {
485                                 let name = self.tcx.item_name(def_id).as_str();
486                                 match fn_ty.sig.0.output {
487                                     ty::FnConverging(ty) => {
488                                         let size = self.type_size(ty, self.substs());
489                                         let ret = return_ptr.unwrap();
490                                         self.call_intrinsic(&name, substs, args, ret, size)?
491                                     }
492                                     ty::FnDiverging => unimplemented!(),
493                                 }
494                             }
495
496                             Abi::C => {
497                                 match fn_ty.sig.0.output {
498                                     ty::FnConverging(ty) => {
499                                         let size = self.type_size(ty, self.substs());
500                                         self.call_c_abi(def_id, args, return_ptr.unwrap(), size)?
501                                     }
502                                     ty::FnDiverging => unimplemented!(),
503                                 }
504                             }
505
506                             Abi::Rust | Abi::RustCall => {
507                                 // TODO(solson): Adjust the first argument when calling a Fn or
508                                 // FnMut closure via FnOnce::call_once.
509
510                                 // Only trait methods can have a Self parameter.
511                                 let (resolved_def_id, resolved_substs) = if substs.self_ty().is_some() {
512                                     self.trait_method(def_id, substs)
513                                 } else {
514                                     (def_id, substs)
515                                 };
516
517                                 let mut arg_srcs = Vec::new();
518                                 for arg in args {
519                                     let src = self.eval_operand(arg)?;
520                                     let src_ty = self.operand_ty(arg);
521                                     arg_srcs.push((src, src_ty));
522                                 }
523
524                                 if fn_ty.abi == Abi::RustCall && !args.is_empty() {
525                                     arg_srcs.pop();
526                                     let last_arg = args.last().unwrap();
527                                     let last = self.eval_operand(last_arg)?;
528                                     let last_ty = self.operand_ty(last_arg);
529                                     let last_layout = self.type_layout(last_ty, self.substs());
530                                     match (&last_ty.sty, last_layout) {
531                                         (&ty::TyTuple(fields),
532                                          &Layout::Univariant { ref variant, .. }) => {
533                                             let offsets = iter::once(0)
534                                                 .chain(variant.offset_after_field.iter()
535                                                     .map(|s| s.bytes()));
536                                             for (offset, ty) in offsets.zip(fields) {
537                                                 let src = last.offset(offset as isize);
538                                                 arg_srcs.push((src, ty));
539                                             }
540                                         }
541                                         ty => panic!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
542                                     }
543                                 }
544
545                                 let mir = self.load_mir(resolved_def_id);
546                                 self.push_stack_frame(def_id, terminator.span, mir, resolved_substs, return_ptr);
547
548                                 for (i, (src, src_ty)) in arg_srcs.into_iter().enumerate() {
549                                     let dest = self.frame().locals[i];
550                                     self.move_(src, dest, src_ty)?;
551                                 }
552
553                                 TerminatorTarget::Call
554                             }
555
556                             abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
557                         }
558                     }
559
560                     _ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))),
561                 }
562             }
563
564             Drop { ref value, target, .. } => {
565                 let ptr = self.eval_lvalue(value)?.to_ptr();
566                 let ty = self.lvalue_ty(value);
567                 self.drop(ptr, ty)?;
568                 self.frame_mut().next_block = target;
569                 TerminatorTarget::Block
570             }
571
572             Resume => unimplemented!(),
573         };
574
575         Ok(target)
576     }
577
578     fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
579         if !self.type_needs_drop(ty) {
580             debug!("no need to drop {:?}", ty);
581             return Ok(());
582         }
583         trace!("-need to drop {:?}", ty);
584
585         // TODO(solson): Call user-defined Drop::drop impls.
586
587         match ty.sty {
588             ty::TyBox(contents_ty) => {
589                 match self.memory.read_ptr(ptr) {
590                     Ok(contents_ptr) => {
591                         self.drop(contents_ptr, contents_ty)?;
592                         trace!("-deallocating box");
593                         self.memory.deallocate(contents_ptr)?;
594                     }
595                     Err(EvalError::ReadBytesAsPointer) => {
596                         let size = self.memory.pointer_size;
597                         let possible_drop_fill = self.memory.read_bytes(ptr, size)?;
598                         if possible_drop_fill.iter().all(|&b| b == mem::POST_DROP_U8) {
599                             return Ok(());
600                         } else {
601                             return Err(EvalError::ReadBytesAsPointer);
602                         }
603                     }
604                     Err(e) => return Err(e),
605                 }
606             }
607
608             // TODO(solson): Implement drop for other relevant types (e.g. aggregates).
609             _ => {}
610         }
611
612         // Filling drop.
613         // FIXME(solson): Trait objects (with no static size) probably get filled, too.
614         let size = self.type_size(ty, self.substs());
615         self.memory.drop_fill(ptr, size)?;
616
617         Ok(())
618     }
619
620     fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
621         use rustc::ty::layout::Layout::*;
622         let adt_layout = self.type_layout(adt_ty, self.substs());
623
624         let discr_val = match *adt_layout {
625             General { discr, .. } | CEnum { discr, .. } => {
626                 let discr_size = discr.size().bytes();
627                 self.memory.read_uint(adt_ptr, discr_size as usize)?
628             }
629
630             RawNullablePointer { nndiscr, .. } => {
631                 self.read_nonnull_discriminant_value(adt_ptr, nndiscr)?
632             }
633
634             StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
635                 let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?;
636                 let nonnull = adt_ptr.offset(offset.bytes() as isize);
637                 self.read_nonnull_discriminant_value(nonnull, nndiscr)?
638             }
639
640             // The discriminant_value intrinsic returns 0 for non-sum types.
641             Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
642             Vector { .. } => 0,
643         };
644
645         Ok(discr_val)
646     }
647
648     fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
649         let not_null = match self.memory.read_usize(ptr) {
650             Ok(0) => false,
651             Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
652             Err(e) => return Err(e),
653         };
654         assert!(nndiscr == 0 || nndiscr == 1);
655         Ok(if not_null { nndiscr } else { 1 - nndiscr })
656     }
657
658     fn call_intrinsic(
659         &mut self,
660         name: &str,
661         substs: &'tcx Substs<'tcx>,
662         args: &[mir::Operand<'tcx>],
663         dest: Pointer,
664         dest_size: usize
665     ) -> EvalResult<TerminatorTarget> {
666         let args_res: EvalResult<Vec<Pointer>> = args.iter()
667             .map(|arg| self.eval_operand(arg))
668             .collect();
669         let args = args_res?;
670
671         match name {
672             // FIXME(solson): Handle different integer types correctly.
673             "add_with_overflow" => {
674                 let ty = *substs.types.get(subst::FnSpace, 0);
675                 let size = self.type_size(ty, self.substs());
676                 let left = self.memory.read_int(args[0], size)?;
677                 let right = self.memory.read_int(args[1], size)?;
678                 let (n, overflowed) = unsafe {
679                     ::std::intrinsics::add_with_overflow::<i64>(left, right)
680                 };
681                 self.memory.write_int(dest, n, size)?;
682                 self.memory.write_bool(dest.offset(size as isize), overflowed)?;
683             }
684
685             "assume" => {}
686
687             "copy_nonoverlapping" => {
688                 let elem_ty = *substs.types.get(subst::FnSpace, 0);
689                 let elem_size = self.type_size(elem_ty, self.substs());
690                 let src = self.memory.read_ptr(args[0])?;
691                 let dest = self.memory.read_ptr(args[1])?;
692                 let count = self.memory.read_isize(args[2])?;
693                 self.memory.copy(src, dest, count as usize * elem_size)?;
694             }
695
696             "discriminant_value" => {
697                 let ty = *substs.types.get(subst::FnSpace, 0);
698                 let adt_ptr = self.memory.read_ptr(args[0])?;
699                 let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
700                 self.memory.write_uint(dest, discr_val, dest_size)?;
701             }
702
703             "forget" => {
704                 let arg_ty = *substs.types.get(subst::FnSpace, 0);
705                 let arg_size = self.type_size(arg_ty, self.substs());
706                 self.memory.drop_fill(args[0], arg_size)?;
707             }
708
709             "init" => self.memory.write_repeat(dest, 0, dest_size)?,
710
711             "min_align_of" => {
712                 self.memory.write_int(dest, 1, dest_size)?;
713             }
714
715             "move_val_init" => {
716                 let ty = *substs.types.get(subst::FnSpace, 0);
717                 let ptr = self.memory.read_ptr(args[0])?;
718                 self.move_(args[1], ptr, ty)?;
719             }
720
721             // FIXME(solson): Handle different integer types correctly.
722             "mul_with_overflow" => {
723                 let ty = *substs.types.get(subst::FnSpace, 0);
724                 let size = self.type_size(ty, self.substs());
725                 let left = self.memory.read_int(args[0], size)?;
726                 let right = self.memory.read_int(args[1], size)?;
727                 let (n, overflowed) = unsafe {
728                     ::std::intrinsics::mul_with_overflow::<i64>(left, right)
729                 };
730                 self.memory.write_int(dest, n, size)?;
731                 self.memory.write_bool(dest.offset(size as isize), overflowed)?;
732             }
733
734             "offset" => {
735                 let pointee_ty = *substs.types.get(subst::FnSpace, 0);
736                 let pointee_size = self.type_size(pointee_ty, self.substs()) as isize;
737                 let ptr_arg = args[0];
738                 let offset = self.memory.read_isize(args[1])?;
739
740                 match self.memory.read_ptr(ptr_arg) {
741                     Ok(ptr) => {
742                         let result_ptr = ptr.offset(offset as isize * pointee_size);
743                         self.memory.write_ptr(dest, result_ptr)?;
744                     }
745                     Err(EvalError::ReadBytesAsPointer) => {
746                         let addr = self.memory.read_isize(ptr_arg)?;
747                         let result_addr = addr + offset * pointee_size as i64;
748                         self.memory.write_isize(dest, result_addr)?;
749                     }
750                     Err(e) => return Err(e),
751                 }
752             }
753
754             // FIXME(solson): Handle different integer types correctly. Use primvals?
755             "overflowing_sub" => {
756                 let ty = *substs.types.get(subst::FnSpace, 0);
757                 let size = self.type_size(ty, self.substs());
758                 let left = self.memory.read_int(args[0], size)?;
759                 let right = self.memory.read_int(args[1], size)?;
760                 let n = left.wrapping_sub(right);
761                 self.memory.write_int(dest, n, size)?;
762             }
763
764             "size_of" => {
765                 let ty = *substs.types.get(subst::FnSpace, 0);
766                 let size = self.type_size(ty, self.substs()) as u64;
767                 self.memory.write_uint(dest, size, dest_size)?;
768             }
769
770             "size_of_val" => {
771                 let ty = *substs.types.get(subst::FnSpace, 0);
772                 if self.type_is_sized(ty) {
773                     let size = self.type_size(ty, self.substs()) as u64;
774                     self.memory.write_uint(dest, size, dest_size)?;
775                 } else {
776                     match ty.sty {
777                         ty::TySlice(_) | ty::TyStr => {
778                             let elem_ty = ty.sequence_element_type(self.tcx);
779                             let elem_size = self.type_size(elem_ty, self.substs()) as u64;
780                             let ptr_size = self.memory.pointer_size as isize;
781                             let n = self.memory.read_usize(args[0].offset(ptr_size))?;
782                             self.memory.write_uint(dest, n * elem_size, dest_size)?;
783                         }
784
785                         _ => return Err(EvalError::Unimplemented(format!("unimplemented: size_of_val::<{:?}>", ty))),
786                     }
787                 }
788             }
789
790             "transmute" => {
791                 let ty = *substs.types.get(subst::FnSpace, 0);
792                 self.move_(args[0], dest, ty)?;
793             }
794             "uninit" => self.memory.mark_definedness(dest, dest_size, false)?,
795
796             name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))),
797         }
798
799         // Since we pushed no stack frame, the main loop will act
800         // as if the call just completed and it's returning to the
801         // current frame.
802         Ok(TerminatorTarget::Call)
803     }
804
805     fn call_c_abi(
806         &mut self,
807         def_id: DefId,
808         args: &[mir::Operand<'tcx>],
809         dest: Pointer,
810         dest_size: usize,
811     ) -> EvalResult<TerminatorTarget> {
812         let name = self.tcx.item_name(def_id);
813         let attrs = self.tcx.get_attrs(def_id);
814         let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
815             Some(ln) => ln.clone(),
816             None => name.as_str(),
817         };
818
819         let args_res: EvalResult<Vec<Pointer>> = args.iter()
820             .map(|arg| self.eval_operand(arg))
821             .collect();
822         let args = args_res?;
823
824         match &link_name[..] {
825             "__rust_allocate" => {
826                 let size = self.memory.read_usize(args[0])?;
827                 let ptr = self.memory.allocate(size as usize);
828                 self.memory.write_ptr(dest, ptr)?;
829             }
830
831             "__rust_reallocate" => {
832                 let ptr = self.memory.read_ptr(args[0])?;
833                 let size = self.memory.read_usize(args[2])?;
834                 self.memory.reallocate(ptr, size as usize)?;
835                 self.memory.write_ptr(dest, ptr)?;
836             }
837
838             "memcmp" => {
839                 let left = self.memory.read_ptr(args[0])?;
840                 let right = self.memory.read_ptr(args[1])?;
841                 let n = self.memory.read_usize(args[2])? as usize;
842
843                 let result = {
844                     let left_bytes = self.memory.read_bytes(left, n)?;
845                     let right_bytes = self.memory.read_bytes(right, n)?;
846
847                     use std::cmp::Ordering::*;
848                     match left_bytes.cmp(right_bytes) {
849                         Less => -1,
850                         Equal => 0,
851                         Greater => 1,
852                     }
853                 };
854
855                 self.memory.write_int(dest, result, dest_size)?;
856             }
857
858             _ => return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name))),
859         }
860
861         // Since we pushed no stack frame, the main loop will act
862         // as if the call just completed and it's returning to the
863         // current frame.
864         Ok(TerminatorTarget::Call)
865     }
866
867     fn assign_fields<I: IntoIterator<Item = u64>>(
868         &mut self,
869         dest: Pointer,
870         offsets: I,
871         operands: &[mir::Operand<'tcx>],
872     ) -> EvalResult<()> {
873         for (offset, operand) in offsets.into_iter().zip(operands) {
874             let src = self.eval_operand(operand)?;
875             let src_ty = self.operand_ty(operand);
876             let field_dest = dest.offset(offset as isize);
877             self.move_(src, field_dest, src_ty)?;
878         }
879         Ok(())
880     }
881
882     fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'tcx>)
883         -> EvalResult<()>
884     {
885         let dest = self.eval_lvalue(lvalue)?.to_ptr();
886         let dest_ty = self.lvalue_ty(lvalue);
887         let dest_layout = self.type_layout(dest_ty, self.substs());
888
889         use rustc::mir::repr::Rvalue::*;
890         match *rvalue {
891             Use(ref operand) => {
892                 let src = self.eval_operand(operand)?;
893                 self.move_(src, dest, dest_ty)?;
894             }
895
896             BinaryOp(bin_op, ref left, ref right) => {
897                 let left_ptr = self.eval_operand(left)?;
898                 let left_ty = self.operand_ty(left);
899                 let left_val = self.read_primval(left_ptr, left_ty)?;
900
901                 let right_ptr = self.eval_operand(right)?;
902                 let right_ty = self.operand_ty(right);
903                 let right_val = self.read_primval(right_ptr, right_ty)?;
904
905                 let val = primval::binary_op(bin_op, left_val, right_val)?;
906                 self.memory.write_primval(dest, val)?;
907             }
908
909             UnaryOp(un_op, ref operand) => {
910                 let ptr = self.eval_operand(operand)?;
911                 let ty = self.operand_ty(operand);
912                 let val = self.read_primval(ptr, ty)?;
913                 self.memory.write_primval(dest, primval::unary_op(un_op, val)?)?;
914             }
915
916             Aggregate(ref kind, ref operands) => {
917                 use rustc::ty::layout::Layout::*;
918                 match *dest_layout {
919                     Univariant { ref variant, .. } => {
920                         let offsets = iter::once(0)
921                             .chain(variant.offset_after_field.iter().map(|s| s.bytes()));
922                         self.assign_fields(dest, offsets, operands)?;
923                     }
924
925                     Array { .. } => {
926                         let elem_size = match dest_ty.sty {
927                             ty::TyArray(elem_ty, _) => self.type_size(elem_ty, self.substs()) as u64,
928                             _ => panic!("tried to assign {:?} to non-array type {:?}",
929                                         kind, dest_ty),
930                         };
931                         let offsets = (0..).map(|i| i * elem_size);
932                         self.assign_fields(dest, offsets, operands)?;
933                     }
934
935                     General { discr, ref variants, .. } => {
936                         if let mir::AggregateKind::Adt(adt_def, variant, _) = *kind {
937                             let discr_val = adt_def.variants[variant].disr_val.to_u64_unchecked();
938                             let discr_size = discr.size().bytes() as usize;
939                             self.memory.write_uint(dest, discr_val, discr_size)?;
940
941                             let offsets = variants[variant].offset_after_field.iter()
942                                 .map(|s| s.bytes());
943                             self.assign_fields(dest, offsets, operands)?;
944                         } else {
945                             panic!("tried to assign {:?} to Layout::General", kind);
946                         }
947                     }
948
949                     RawNullablePointer { nndiscr, .. } => {
950                         if let mir::AggregateKind::Adt(_, variant, _) = *kind {
951                             if nndiscr == variant as u64 {
952                                 assert_eq!(operands.len(), 1);
953                                 let operand = &operands[0];
954                                 let src = self.eval_operand(operand)?;
955                                 let src_ty = self.operand_ty(operand);
956                                 self.move_(src, dest, src_ty)?;
957                             } else {
958                                 assert_eq!(operands.len(), 0);
959                                 self.memory.write_isize(dest, 0)?;
960                             }
961                         } else {
962                             panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
963                         }
964                     }
965
966                     StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield } => {
967                         if let mir::AggregateKind::Adt(_, variant, _) = *kind {
968                             if nndiscr == variant as u64 {
969                                 let offsets = iter::once(0)
970                                     .chain(nonnull.offset_after_field.iter().map(|s| s.bytes()));
971                                 try!(self.assign_fields(dest, offsets, operands));
972                             } else {
973                                 assert_eq!(operands.len(), 0);
974                                 let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
975                                 let dest = dest.offset(offset.bytes() as isize);
976                                 try!(self.memory.write_isize(dest, 0));
977                             }
978                         } else {
979                             panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
980                         }
981                     }
982
983                     CEnum { discr, signed, .. } => {
984                         assert_eq!(operands.len(), 0);
985                         if let mir::AggregateKind::Adt(adt_def, variant, _) = *kind {
986                             let val = adt_def.variants[variant].disr_val.to_u64_unchecked();
987                             let size = discr.size().bytes() as usize;
988
989                             if signed {
990                                 self.memory.write_int(dest, val as i64, size)?;
991                             } else {
992                                 self.memory.write_uint(dest, val, size)?;
993                             }
994                         } else {
995                             panic!("tried to assign {:?} to Layout::CEnum", kind);
996                         }
997                     }
998
999                     _ => return Err(EvalError::Unimplemented(format!("can't handle destination layout {:?} when assigning {:?}", dest_layout, kind))),
1000                 }
1001             }
1002
1003             Repeat(ref operand, _) => {
1004                 let (elem_size, length) = match dest_ty.sty {
1005                     ty::TyArray(elem_ty, n) => (self.type_size(elem_ty, self.substs()), n),
1006                     _ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty),
1007                 };
1008
1009                 let src = self.eval_operand(operand)?;
1010                 for i in 0..length {
1011                     let elem_dest = dest.offset((i * elem_size) as isize);
1012                     self.memory.copy(src, elem_dest, elem_size)?;
1013                 }
1014             }
1015
1016             Len(ref lvalue) => {
1017                 let src = self.eval_lvalue(lvalue)?;
1018                 let ty = self.lvalue_ty(lvalue);
1019                 let len = match ty.sty {
1020                     ty::TyArray(_, n) => n as u64,
1021                     ty::TySlice(_) => if let LvalueExtra::Length(n) = src.extra {
1022                         n
1023                     } else {
1024                         panic!("Rvalue::Len of a slice given non-slice pointer: {:?}", src);
1025                     },
1026                     _ => panic!("Rvalue::Len expected array or slice, got {:?}", ty),
1027                 };
1028                 self.memory.write_usize(dest, len)?;
1029             }
1030
1031             Ref(_, _, ref lvalue) => {
1032                 let lv = self.eval_lvalue(lvalue)?;
1033                 self.memory.write_ptr(dest, lv.ptr)?;
1034                 match lv.extra {
1035                     LvalueExtra::None => {},
1036                     LvalueExtra::Length(len) => {
1037                         let len_ptr = dest.offset(self.memory.pointer_size as isize);
1038                         self.memory.write_usize(len_ptr, len)?;
1039                     }
1040                     LvalueExtra::DowncastVariant(..) =>
1041                         panic!("attempted to take a reference to an enum downcast lvalue"),
1042                 }
1043             }
1044
1045             Box(ty) => {
1046                 let size = self.type_size(ty, self.substs());
1047                 let ptr = self.memory.allocate(size);
1048                 self.memory.write_ptr(dest, ptr)?;
1049             }
1050
1051             Cast(kind, ref operand, dest_ty) => {
1052                 let src = self.eval_operand(operand)?;
1053                 let src_ty = self.operand_ty(operand);
1054
1055                 use rustc::mir::repr::CastKind::*;
1056                 match kind {
1057                     Unsize => {
1058                         self.move_(src, dest, src_ty)?;
1059                         let src_pointee_ty = pointee_type(src_ty).unwrap();
1060                         let dest_pointee_ty = pointee_type(dest_ty).unwrap();
1061
1062                         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1063                             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1064                                 let len_ptr = dest.offset(self.memory.pointer_size as isize);
1065                                 self.memory.write_usize(len_ptr, length as u64)?;
1066                             }
1067
1068                             _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
1069                         }
1070                     }
1071
1072                     Misc => {
1073                         // FIXME(solson): Wrong for almost everything.
1074                         let size = dest_layout.size(&self.tcx.data_layout).bytes() as usize;
1075                         self.memory.copy(src, dest, size)?;
1076                     }
1077
1078                     _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
1079                 }
1080             }
1081
1082             Slice { .. } => unimplemented!(),
1083             InlineAsm { .. } => unimplemented!(),
1084         }
1085
1086         Ok(())
1087     }
1088
1089     fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<Size> {
1090         // Skip the constant 0 at the start meant for LLVM GEP.
1091         let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
1092
1093         // Handle the field index for the outer non-null variant.
1094         let inner_ty = match ty.sty {
1095             ty::TyEnum(adt_def, substs) => {
1096                 let variant = &adt_def.variants[nndiscr as usize];
1097                 let index = path.next().unwrap();
1098                 let field = &variant.fields[index];
1099                 field.ty(self.tcx, substs)
1100             }
1101             _ => panic!(
1102                 "non-enum for StructWrappedNullablePointer: {}",
1103                 ty,
1104             ),
1105         };
1106
1107         self.field_path_offset(inner_ty, path)
1108     }
1109
1110     fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
1111         let mut offset = Size::from_bytes(0);
1112
1113         // Skip the initial 0 intended for LLVM GEP.
1114         for field_index in path {
1115             let field_offset = self.get_field_offset(ty, field_index)?;
1116             ty = self.get_field_ty(ty, field_index)?;
1117             offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
1118         }
1119
1120         Ok(offset)
1121     }
1122
1123     fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
1124         match ty.sty {
1125             ty::TyStruct(adt_def, substs) => {
1126                 Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
1127             }
1128
1129             ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1130             ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
1131             ty::TyBox(ty) => {
1132                 assert_eq!(field_index, 0);
1133                 Ok(ty)
1134             }
1135             _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}", ty))),
1136         }
1137     }
1138
1139     fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
1140         let layout = self.type_layout(ty, self.substs());
1141
1142         use rustc::ty::layout::Layout::*;
1143         match *layout {
1144             Univariant { .. } => {
1145                 assert_eq!(field_index, 0);
1146                 Ok(Size::from_bytes(0))
1147             }
1148             FatPointer { .. } => {
1149                 let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
1150                 Ok(Size::from_bytes(bytes as u64))
1151             }
1152             _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))),
1153         }
1154     }
1155
1156     fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
1157         use rustc::mir::repr::Operand::*;
1158         match *op {
1159             Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()),
1160             Constant(mir::Constant { ref literal, ty, .. }) => {
1161                 use rustc::mir::repr::Literal::*;
1162                 match *literal {
1163                     Value { ref value } => Ok(self.const_to_ptr(value)?),
1164                     Item { def_id, substs } => {
1165                         if let ty::TyFnDef(..) = ty.sty {
1166                             Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string()))
1167                         } else {
1168                             let cid = ConstantId {
1169                                 def_id: def_id,
1170                                 substs: substs,
1171                                 kind: ConstantKind::Global,
1172                             };
1173                             Ok(*self.statics.get(&cid).expect("static should have been cached (rvalue)"))
1174                         }
1175                     },
1176                     Promoted { index } => {
1177                         let cid = ConstantId {
1178                             def_id: self.frame().def_id,
1179                             substs: self.substs(),
1180                             kind: ConstantKind::Promoted(index),
1181                         };
1182                         Ok(*self.statics.get(&cid).expect("a promoted constant hasn't been precomputed"))
1183                     },
1184                 }
1185             }
1186         }
1187     }
1188
1189     fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
1190         use rustc::mir::repr::Lvalue::*;
1191         let ptr = match *lvalue {
1192             ReturnPointer => self.frame().return_ptr
1193                 .expect("ReturnPointer used in a function with no return value"),
1194             Arg(i) => self.frame().locals[i as usize],
1195             Var(i) => self.frame().locals[self.frame().var_offset + i as usize],
1196             Temp(i) => self.frame().locals[self.frame().temp_offset + i as usize],
1197
1198             Static(def_id) => {
1199                 let substs = self.tcx.mk_substs(subst::Substs::empty());
1200                 let cid = ConstantId {
1201                     def_id: def_id,
1202                     substs: substs,
1203                     kind: ConstantKind::Global,
1204                 };
1205                 *self.statics.get(&cid).expect("static should have been cached (lvalue)")
1206             },
1207
1208             Projection(ref proj) => {
1209                 let base = self.eval_lvalue(&proj.base)?;
1210                 let base_ty = self.lvalue_ty(&proj.base);
1211                 let base_layout = self.type_layout(base_ty, self.substs());
1212
1213                 use rustc::mir::repr::ProjectionElem::*;
1214                 match proj.elem {
1215                     Field(field, _) => {
1216                         use rustc::ty::layout::Layout::*;
1217                         let variant = match *base_layout {
1218                             Univariant { ref variant, .. } => variant,
1219                             General { ref variants, .. } => {
1220                                 if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
1221                                     &variants[variant_idx]
1222                                 } else {
1223                                     panic!("field access on enum had no variant index");
1224                                 }
1225                             }
1226                             RawNullablePointer { .. } => {
1227                                 assert_eq!(field.index(), 0);
1228                                 return Ok(base);
1229                             }
1230                             StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
1231                             _ => panic!("field access on non-product type: {:?}", base_layout),
1232                         };
1233
1234                         let offset = variant.field_offset(field.index()).bytes();
1235                         base.ptr.offset(offset as isize)
1236                     },
1237
1238                     Downcast(_, variant) => {
1239                         use rustc::ty::layout::Layout::*;
1240                         match *base_layout {
1241                             General { discr, .. } => {
1242                                 return Ok(Lvalue {
1243                                     ptr: base.ptr.offset(discr.size().bytes() as isize),
1244                                     extra: LvalueExtra::DowncastVariant(variant),
1245                                 });
1246                             }
1247                             RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1248                                 return Ok(base);
1249                             }
1250                             _ => panic!("variant downcast on non-aggregate: {:?}", base_layout),
1251                         }
1252                     },
1253
1254                     Deref => {
1255                         let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer");
1256                         let ptr = self.memory.read_ptr(base.ptr)?;
1257                         let extra = match pointee_ty.sty {
1258                             ty::TySlice(_) | ty::TyStr => {
1259                                 let len_ptr = base.ptr.offset(self.memory.pointer_size as isize);
1260                                 let len = self.memory.read_usize(len_ptr)?;
1261                                 LvalueExtra::Length(len)
1262                             }
1263                             ty::TyTrait(_) => unimplemented!(),
1264                             _ => LvalueExtra::None,
1265                         };
1266                         return Ok(Lvalue { ptr: ptr, extra: extra });
1267                     }
1268
1269                     Index(ref operand) => {
1270                         let elem_size = match base_ty.sty {
1271                             ty::TyArray(elem_ty, _) |
1272                             ty::TySlice(elem_ty) => self.type_size(elem_ty, self.substs()),
1273                             _ => panic!("indexing expected an array or slice, got {:?}", base_ty),
1274                         };
1275                         let n_ptr = self.eval_operand(operand)?;
1276                         let n = self.memory.read_usize(n_ptr)?;
1277                         base.ptr.offset(n as isize * elem_size as isize)
1278                     }
1279
1280                     ConstantIndex { .. } => unimplemented!(),
1281                 }
1282             }
1283         };
1284
1285         Ok(Lvalue { ptr: ptr, extra: LvalueExtra::None })
1286     }
1287
1288     fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
1289         self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx), self.substs())
1290     }
1291
1292     fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
1293         self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
1294     }
1295
1296     fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
1297         let size = self.type_size(ty, self.substs());
1298         self.memory.copy(src, dest, size)?;
1299         if self.type_needs_drop(ty) {
1300             self.memory.drop_fill(src, size)?;
1301         }
1302         Ok(())
1303     }
1304
1305     pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
1306         use syntax::ast::{IntTy, UintTy};
1307         let val = match (self.memory.pointer_size, &ty.sty) {
1308             (_, &ty::TyBool)              => PrimVal::Bool(self.memory.read_bool(ptr)?),
1309             (_, &ty::TyInt(IntTy::I8))    => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
1310             (2, &ty::TyInt(IntTy::Is)) |
1311             (_, &ty::TyInt(IntTy::I16))   => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
1312             (4, &ty::TyInt(IntTy::Is)) |
1313             (_, &ty::TyInt(IntTy::I32))   => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
1314             (8, &ty::TyInt(IntTy::Is)) |
1315             (_, &ty::TyInt(IntTy::I64))   => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
1316             (_, &ty::TyUint(UintTy::U8))  => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
1317             (2, &ty::TyUint(UintTy::Us)) |
1318             (_, &ty::TyUint(UintTy::U16)) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
1319             (4, &ty::TyUint(UintTy::Us)) |
1320             (_, &ty::TyUint(UintTy::U32)) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
1321             (8, &ty::TyUint(UintTy::Us)) |
1322             (_, &ty::TyUint(UintTy::U64)) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
1323
1324             (_, &ty::TyRef(_, ty::TypeAndMut { ty, .. })) |
1325             (_, &ty::TyRawPtr(ty::TypeAndMut { ty, .. })) => {
1326                 if self.type_is_sized(ty) {
1327                     match self.memory.read_ptr(ptr) {
1328                         Ok(p) => PrimVal::AbstractPtr(p),
1329                         Err(EvalError::ReadBytesAsPointer) => {
1330                             PrimVal::IntegerPtr(self.memory.read_usize(ptr)?)
1331                         }
1332                         Err(e) => return Err(e),
1333                     }
1334                 } else {
1335                     return Err(EvalError::Unimplemented(format!("unimplemented: primitive read of fat pointer type: {:?}", ty)));
1336                 }
1337             }
1338
1339             _ => panic!("primitive read of non-primitive type: {:?}", ty),
1340         };
1341         Ok(val)
1342     }
1343
1344     fn frame(&self) -> &Frame<'a, 'tcx> {
1345         self.stack.last().expect("no call frames exist")
1346     }
1347
1348     fn basic_block(&self) -> &mir::BasicBlockData<'tcx> {
1349         let frame = self.frame();
1350         frame.mir.basic_block_data(frame.next_block)
1351     }
1352
1353     fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
1354         self.stack.last_mut().expect("no call frames exist")
1355     }
1356
1357     fn mir(&self) -> CachedMir<'a, 'tcx> {
1358         self.frame().mir.clone()
1359     }
1360
1361     fn substs(&self) -> &'tcx Substs<'tcx> {
1362         self.frame().substs
1363     }
1364 }
1365
1366 fn pointee_type(ptr_ty: ty::Ty) -> Option<ty::Ty> {
1367     match ptr_ty.sty {
1368         ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1369         ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
1370         ty::TyBox(ty) => {
1371             Some(ty)
1372         }
1373         _ => None,
1374     }
1375 }
1376
1377 impl Lvalue {
1378     fn to_ptr(self) -> Pointer {
1379         assert_eq!(self.extra, LvalueExtra::None);
1380         self.ptr
1381     }
1382 }
1383
1384 impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> {
1385     type Target = mir::Mir<'tcx>;
1386     fn deref(&self) -> &mir::Mir<'tcx> {
1387         match *self {
1388             CachedMir::Ref(r) => r,
1389             CachedMir::Owned(ref rc) => rc,
1390         }
1391     }
1392 }
1393
1394 #[derive(Debug)]
1395 pub struct ImplMethod<'tcx> {
1396     pub method: Rc<ty::Method<'tcx>>,
1397     pub substs: &'tcx Substs<'tcx>,
1398     pub is_provided: bool,
1399 }
1400
1401 /// Locates the applicable definition of a method, given its name.
1402 pub fn get_impl_method<'a, 'tcx>(
1403     tcx: TyCtxt<'a, 'tcx, 'tcx>,
1404     impl_def_id: DefId,
1405     substs: &'tcx Substs<'tcx>,
1406     name: ast::Name,
1407 ) -> ImplMethod<'tcx> {
1408     assert!(!substs.types.needs_infer());
1409
1410     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
1411     let trait_def = tcx.lookup_trait_def(trait_def_id);
1412
1413     match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
1414         Some(node_item) => {
1415             let substs = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
1416                 let substs = traits::translate_substs(&infcx, impl_def_id,
1417                                                       substs, node_item.node);
1418                 tcx.lift(&substs).unwrap_or_else(|| {
1419                     bug!("trans::meth::get_impl_method: translate_substs \
1420                           returned {:?} which contains inference types/regions",
1421                          substs);
1422                 })
1423             });
1424             ImplMethod {
1425                 method: node_item.item,
1426                 substs: substs,
1427                 is_provided: node_item.node.is_from_trait(),
1428             }
1429         }
1430         None => {
1431             bug!("method {:?} not found in {:?}", name, impl_def_id)
1432         }
1433     }
1434 }
1435
1436 pub fn interpret_start_points<'a, 'tcx>(
1437     tcx: TyCtxt<'a, 'tcx, 'tcx>,
1438     mir_map: &MirMap<'tcx>,
1439 ) {
1440     let initial_indentation = ::log_settings::settings().indentation;
1441     for (&id, mir) in &mir_map.map {
1442         for attr in tcx.map.attrs(id) {
1443             use syntax::attr::AttrMetaMethods;
1444             if attr.check_name("miri_run") {
1445                 let item = tcx.map.expect_item(id);
1446
1447                 ::log_settings::settings().indentation = initial_indentation;
1448
1449                 debug!("Interpreting: {}", item.name);
1450
1451                 let mut gecx = GlobalEvalContext::new(tcx, mir_map);
1452                 match gecx.call(mir, tcx.map.local_def_id(id)) {
1453                     Ok(Some(return_ptr)) => if log_enabled!(::log::LogLevel::Debug) {
1454                         gecx.memory.dump(return_ptr.alloc_id);
1455                     },
1456                     Ok(None) => warn!("diverging function returned"),
1457                     Err(_e) => {
1458                         // TODO(solson): Detect whether the error was already reported or not.
1459                         // tcx.sess.err(&e.to_string());
1460                     }
1461                 }
1462             }
1463         }
1464     }
1465 }
1466
1467 // TODO(solson): Upstream these methods into rustc::ty::layout.
1468
1469 trait IntegerExt {
1470     fn size(self) -> Size;
1471 }
1472
1473 impl IntegerExt for layout::Integer {
1474     fn size(self) -> Size {
1475         use rustc::ty::layout::Integer::*;
1476         match self {
1477             I1 | I8 => Size::from_bits(8),
1478             I16 => Size::from_bits(16),
1479             I32 => Size::from_bits(32),
1480             I64 => Size::from_bits(64),
1481         }
1482     }
1483 }
1484
1485 trait StructExt {
1486     fn field_offset(&self, index: usize) -> Size;
1487 }
1488
1489 impl StructExt for layout::Struct {
1490     fn field_offset(&self, index: usize) -> Size {
1491         if index == 0 {
1492             Size::from_bytes(0)
1493         } else {
1494             self.offset_after_field[index - 1]
1495         }
1496     }
1497 }