Handle promoted rvalues by recursing with call_nested.
This commit is contained in:
parent
49b6349577
commit
753971a4c5
1 changed files with 70 additions and 29 deletions
|
|
@ -10,7 +10,7 @@ use rustc::ty::subst::{self, Subst, Substs};
|
|||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::util::nodemap::DefIdMap;
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::{iter, mem};
|
||||
use syntax::ast;
|
||||
|
|
@ -23,7 +23,7 @@ use primval::{self, PrimVal};
|
|||
|
||||
const TRACE_EXECUTION: bool = false;
|
||||
|
||||
struct Interpreter<'a, 'tcx: 'a> {
|
||||
struct GlobalEvalContext<'a, 'tcx: 'a> {
|
||||
/// The results of the type checker, from rustc.
|
||||
tcx: &'a TyCtxt<'tcx>,
|
||||
|
||||
|
|
@ -36,9 +36,6 @@ struct Interpreter<'a, 'tcx: 'a> {
|
|||
/// The virtual memory system.
|
||||
memory: Memory,
|
||||
|
||||
/// The virtual call stack.
|
||||
stack: Vec<Frame<'a, 'tcx>>,
|
||||
|
||||
/// Another stack containing the type substitutions for the current function invocation. It
|
||||
/// exists separately from `stack` because it must contain the `Substs` for a function while
|
||||
/// *creating* the `Frame` for that same function.
|
||||
|
|
@ -51,6 +48,26 @@ struct Interpreter<'a, 'tcx: 'a> {
|
|||
name_stack: Vec<(DefId, &'tcx Substs<'tcx>, codemap::Span)>,
|
||||
}
|
||||
|
||||
struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> {
|
||||
gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
|
||||
|
||||
/// The virtual call stack.
|
||||
stack: Vec<Frame<'mir, 'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> Deref for FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
type Target = GlobalEvalContext<'b, 'tcx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.gecx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> DerefMut for FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.gecx
|
||||
}
|
||||
}
|
||||
|
||||
/// A stack frame.
|
||||
struct Frame<'a, 'tcx: 'a> {
|
||||
/// The MIR for the function called on this frame.
|
||||
|
|
@ -106,18 +123,26 @@ enum TerminatorTarget {
|
|||
Return,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||
impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
||||
fn new(tcx: &'a TyCtxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
|
||||
Interpreter {
|
||||
GlobalEvalContext {
|
||||
tcx: tcx,
|
||||
mir_map: mir_map,
|
||||
mir_cache: RefCell::new(DefIdMap()),
|
||||
memory: Memory::new(),
|
||||
stack: Vec::new(),
|
||||
substs_stack: Vec::new(),
|
||||
name_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
fn new(gecx: &'a mut GlobalEvalContext<'b, 'tcx>) -> Self {
|
||||
FnEvalContext {
|
||||
gecx: gecx,
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_report<T>(&self, span: codemap::Span, r: EvalResult<T>) -> EvalResult<T> {
|
||||
if let Err(ref e) = r {
|
||||
|
|
@ -183,7 +208,24 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn push_stack_frame(&mut self, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>,
|
||||
fn call_nested(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult<Option<Pointer>> {
|
||||
let mut nested_fecx = FnEvalContext::new(self.gecx);
|
||||
|
||||
let return_ptr = match mir.return_ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = nested_fecx.type_size(ty);
|
||||
Some(nested_fecx.memory.allocate(size))
|
||||
}
|
||||
ty::FnDiverging => None,
|
||||
};
|
||||
|
||||
let substs = nested_fecx.substs();
|
||||
nested_fecx.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr);
|
||||
try!(nested_fecx.run());
|
||||
Ok(return_ptr)
|
||||
}
|
||||
|
||||
fn push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>,
|
||||
return_ptr: Option<Pointer>)
|
||||
{
|
||||
self.substs_stack.push(substs);
|
||||
|
|
@ -805,7 +847,11 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
|||
match *literal {
|
||||
Value { ref value } => Ok(try!(self.const_to_ptr(value))),
|
||||
Item { .. } => unimplemented!(),
|
||||
Promoted { .. } => unimplemented!(),
|
||||
Promoted { index } => {
|
||||
let current_mir = self.mir();
|
||||
let mir = ¤t_mir.promoted[index];
|
||||
self.call_nested(mir).map(Option::unwrap)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1020,23 +1066,23 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
|||
Ok(val)
|
||||
}
|
||||
|
||||
fn frame(&self) -> &Frame<'a, 'tcx> {
|
||||
fn frame(&self) -> &Frame<'mir, 'tcx> {
|
||||
self.stack.last().expect("no call frames exist")
|
||||
}
|
||||
|
||||
fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
|
||||
fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
|
||||
self.stack.last_mut().expect("no call frames exist")
|
||||
}
|
||||
|
||||
fn mir(&self) -> &mir::Mir<'tcx> {
|
||||
&self.frame().mir
|
||||
fn mir(&self) -> CachedMir<'mir, 'tcx> {
|
||||
self.frame().mir.clone()
|
||||
}
|
||||
|
||||
fn substs(&self) -> &'tcx Substs<'tcx> {
|
||||
self.substs_stack.last().cloned().unwrap_or_else(|| self.tcx.mk_substs(Substs::empty()))
|
||||
}
|
||||
|
||||
fn load_mir(&self, def_id: DefId) -> CachedMir<'a, 'tcx> {
|
||||
fn load_mir(&self, def_id: DefId) -> CachedMir<'mir, 'tcx> {
|
||||
match self.tcx.map.as_local_node_id(def_id) {
|
||||
Some(node_id) => CachedMir::Ref(self.mir_map.map.get(&node_id).unwrap()),
|
||||
None => {
|
||||
|
|
@ -1200,22 +1246,17 @@ pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>)
|
|||
|
||||
println!("Interpreting: {}", item.name);
|
||||
|
||||
let mut miri = Interpreter::new(tcx, mir_map);
|
||||
let return_ptr = match mir.return_ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = miri.type_size(ty);
|
||||
Some(miri.memory.allocate(size))
|
||||
let mut gecx = GlobalEvalContext::new(tcx, mir_map);
|
||||
let mut fecx = FnEvalContext::new(&mut gecx);
|
||||
match fecx.call_nested(mir) {
|
||||
Ok(Some(return_ptr)) => fecx.memory.dump(return_ptr.alloc_id),
|
||||
Ok(None) => println!("(diverging function returned)"),
|
||||
Err(_e) => {
|
||||
// TODO(tsion): Detect whether the error was already reported or not.
|
||||
// tcx.sess.err(&e.to_string());
|
||||
}
|
||||
ty::FnDiverging => None,
|
||||
};
|
||||
let substs = miri.tcx.mk_substs(Substs::empty());
|
||||
miri.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr);
|
||||
if let Err(_e) = miri.run() {
|
||||
// TODO(tsion): Detect whether the error was already reported or not.
|
||||
// tcx.sess.err(&e.to_string());
|
||||
} else if let Some(ret) = return_ptr {
|
||||
miri.memory.dump(ret.alloc_id);
|
||||
}
|
||||
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue