mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-08 07:57:40 +00:00
directly push stackframes for constants when they are encountered
This commit is contained in:
parent
6b939bbd79
commit
8b25bc8a9a
@ -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| {
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user