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