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