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