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