directly push stackframes for constants when they are encountered

This commit is contained in:
Oliver Schneider 2016-06-08 11:11:33 +02:00
parent 6b939bbd79
commit 8b25bc8a9a
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
2 changed files with 42 additions and 35 deletions

View File

@ -14,7 +14,7 @@ use std::rc::Rc;
use std::{iter, mem}; use std::{iter, mem};
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::codemap::{self, DUMMY_SP, Span}; use syntax::codemap::{self, DUMMY_SP};
use error::{EvalError, EvalResult}; use error::{EvalError, EvalResult};
use memory::{Memory, Pointer}; use memory::{Memory, Pointer};
@ -94,9 +94,6 @@ struct Frame<'a, 'tcx: 'a> {
/// The index of the currently evaluated statment /// The index of the currently evaluated statment
stmt: usize, stmt: usize,
// Constants that need to be evaluated before the next statement can be evaluated
constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'a, 'tcx>)>,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -409,7 +406,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
loop { loop {
match stepper.step()? { match stepper.step()? {
Constant => trace!("next statement requires the computation of a constant"), Constant => trace!("computing a constant"),
Assignment => trace!("{:?}", stepper.stmt()), Assignment => trace!("{:?}", stepper.stmt()),
Terminator => { Terminator => {
trace!("{:?}", stepper.term().kind); trace!("{:?}", stepper.term().kind);
@ -444,7 +441,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
def_id: def_id, def_id: def_id,
substs: substs, substs: substs,
stmt: 0, stmt: 0,
constants: Vec::new(),
}); });
let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {

View File

@ -4,7 +4,6 @@ use super::{
TerminatorTarget, TerminatorTarget,
ConstantId, ConstantId,
GlobalEvalContext, GlobalEvalContext,
Frame,
}; };
use error::EvalResult; use error::EvalResult;
use rustc::mir::repr as mir; use rustc::mir::repr as mir;
@ -13,6 +12,7 @@ use rustc::hir::def_id::DefId;
use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::visit::{Visitor, LvalueContext};
use syntax::codemap::Span; use syntax::codemap::Span;
use std::rc::Rc; use std::rc::Rc;
use memory::Pointer;
pub enum Event { pub enum Event {
Constant, Constant,
@ -24,6 +24,10 @@ pub enum Event {
pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
// a cache of the constants to be computed before the next statement/terminator
// this is an optimization, so we don't have to allocate a new vector for every statement
constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
} }
impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> { impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
@ -31,6 +35,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
Stepper { Stepper {
fncx: fncx, fncx: fncx,
process: Self::dummy, process: Self::dummy,
constants: Vec::new(),
} }
} }
@ -60,7 +65,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
match term { match term {
TerminatorTarget::Block => {}, TerminatorTarget::Block => {},
TerminatorTarget::Return => { TerminatorTarget::Return => {
assert!(self.fncx.frame().constants.is_empty());
self.fncx.pop_stack_frame(); self.fncx.pop_stack_frame();
}, },
TerminatorTarget::Call => {}, TerminatorTarget::Call => {},
@ -68,14 +72,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
Ok(()) Ok(())
} }
fn constant(&mut self) -> EvalResult<()> {
let (cid, span, return_ptr, mir) = self.fncx.frame_mut().constants.pop().expect("state machine broken");
let def_id = cid.def_id();
let substs = cid.substs();
self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr));
Ok(())
}
pub fn step(&mut self) -> EvalResult<Event> { pub fn step(&mut self) -> EvalResult<Event> {
(self.process)(self)?; (self.process)(self)?;
@ -85,48 +81,60 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
return Ok(Event::Done); return Ok(Event::Done);
} }
if !self.fncx.frame().constants.is_empty() {
self.process = Self::constant;
return Ok(Event::Constant);
}
let block = self.fncx.frame().next_block; let block = self.fncx.frame().next_block;
let stmt = self.fncx.frame().stmt; let stmt = self.fncx.frame().stmt;
let mir = self.fncx.mir(); let mir = self.fncx.mir();
let basic_block = mir.basic_block_data(block); let basic_block = mir.basic_block_data(block);
if let Some(ref stmt) = basic_block.statements.get(stmt) { if let Some(ref stmt) = basic_block.statements.get(stmt) {
assert!(self.fncx.frame().constants.is_empty()); assert!(self.constants.is_empty());
ConstantExtractor { ConstantExtractor {
span: stmt.span, span: stmt.span,
substs: self.fncx.substs(),
def_id: self.fncx.frame().def_id,
gecx: self.fncx.gecx, gecx: self.fncx.gecx,
frame: self.fncx.stack.last_mut().expect("stack empty"), constants: &mut self.constants,
mir: &mir,
}.visit_statement(block, stmt); }.visit_statement(block, stmt);
if self.fncx.frame().constants.is_empty() { if self.constants.is_empty() {
self.process = Self::statement; self.process = Self::statement;
return Ok(Event::Assignment); return Ok(Event::Assignment);
} else { } else {
self.process = Self::constant; self.process = Self::statement;
self.extract_constants();
return Ok(Event::Constant); return Ok(Event::Constant);
} }
} }
let terminator = basic_block.terminator(); let terminator = basic_block.terminator();
assert!(self.fncx.frame().constants.is_empty()); assert!(self.constants.is_empty());
ConstantExtractor { ConstantExtractor {
span: terminator.span, span: terminator.span,
substs: self.fncx.substs(),
def_id: self.fncx.frame().def_id,
gecx: self.fncx.gecx, gecx: self.fncx.gecx,
frame: self.fncx.stack.last_mut().expect("stack empty"), constants: &mut self.constants,
mir: &mir,
}.visit_terminator(block, terminator); }.visit_terminator(block, terminator);
if self.fncx.frame().constants.is_empty() { if self.constants.is_empty() {
self.process = Self::terminator; self.process = Self::terminator;
Ok(Event::Terminator) Ok(Event::Terminator)
} else { } else {
self.process = Self::constant; self.process = Self::statement;
self.extract_constants();
Ok(Event::Constant) Ok(Event::Constant)
} }
} }
fn extract_constants(&mut self) {
assert!(!self.constants.is_empty());
for (cid, span, return_ptr, mir) in self.constants.drain(..) {
let def_id = cid.def_id();
let substs = cid.substs();
self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr));
}
}
/// returns the statement that will be processed next /// returns the statement that will be processed next
pub fn stmt(&self) -> &mir::Statement { pub fn stmt(&self) -> &mir::Statement {
&self.fncx.basic_block().statements[self.fncx.frame().stmt] &self.fncx.basic_block().statements[self.fncx.frame().stmt]
@ -144,8 +152,11 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> {
span: Span, span: Span,
frame: &'a mut Frame<'mir, 'tcx>, constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
gecx: &'a mut GlobalEvalContext<'b, 'tcx>, gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
mir: &'a mir::Mir<'tcx>,
def_id: DefId,
substs: &'tcx subst::Substs<'tcx>,
} }
impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
@ -160,7 +171,7 @@ impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
let mir = self.gecx.load_mir(def_id); let mir = self.gecx.load_mir(def_id);
let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static"); let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
self.gecx.statics.insert(cid.clone(), ptr); self.gecx.statics.insert(cid.clone(), ptr);
self.frame.constants.push((cid, span, ptr, mir)); self.constants.push((cid, span, ptr, mir));
} }
} }
@ -180,19 +191,19 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx>
}, },
mir::Literal::Promoted { index } => { mir::Literal::Promoted { index } => {
let cid = ConstantId::Promoted { let cid = ConstantId::Promoted {
def_id: self.frame.def_id, def_id: self.def_id,
substs: self.frame.substs, substs: self.substs,
index: index, index: index,
}; };
if self.gecx.statics.contains_key(&cid) { if self.gecx.statics.contains_key(&cid) {
return; return;
} }
let mir = self.frame.mir.promoted[index].clone(); let mir = self.mir.promoted[index].clone();
let return_ty = mir.return_ty; let return_ty = mir.return_ty;
let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs()).expect("there's no such thing as an unreachable static"); let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs()).expect("there's no such thing as an unreachable static");
let mir = CachedMir::Owned(Rc::new(mir)); let mir = CachedMir::Owned(Rc::new(mir));
self.gecx.statics.insert(cid.clone(), return_ptr); self.gecx.statics.insert(cid.clone(), return_ptr);
self.frame.constants.push((cid, constant.span, return_ptr, mir)); self.constants.push((cid, constant.span, return_ptr, mir));
} }
} }
} }