-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hold the state #18
Hold the state #18
Changes from 4 commits
e73fa77
8398781
5a8b0ab
2405c81
77e1ec2
0c269a5
5211178
6ac64f1
97bc1d4
38ae352
05f829c
cc1ca73
f995db9
346560b
02eed64
4743842
dc85b11
4c833a5
4d44a97
f42be6d
c881cf1
1f27d3f
6b939bb
8b25bc8
3de30e3
3868a62
240f0c0
2178961
cbbf58b
59d858a
225a6a2
040a501
05eaa52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use super::{ | ||
FnEvalContext, | ||
CachedMir, | ||
TerminatorTarget, | ||
}; | ||
use error::EvalResult; | ||
use rustc::mir::repr as mir; | ||
|
||
pub enum Event<'a, 'tcx: 'a> { | ||
Assignment(&'a mir::Statement<'tcx>), | ||
Terminator(&'a mir::Terminator<'tcx>), | ||
Done, | ||
} | ||
|
||
pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ | ||
fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, | ||
block: mir::BasicBlock, | ||
stmt: usize, | ||
mir: CachedMir<'mir, 'tcx>, | ||
process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, | ||
} | ||
|
||
impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> { | ||
pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self { | ||
Stepper { | ||
block: fncx.frame().next_block, | ||
mir: fncx.mir(), | ||
fncx: fncx, | ||
stmt: 0, | ||
process: Self::dummy, | ||
} | ||
} | ||
fn dummy(&mut self) -> EvalResult<()> { Ok(()) } | ||
fn statement(&mut self) -> EvalResult<()> { | ||
let block_data = self.mir.basic_block_data(self.block); | ||
let stmt = &block_data.statements[self.stmt]; | ||
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; | ||
let result = self.fncx.eval_assignment(lvalue, rvalue); | ||
self.fncx.maybe_report(stmt.span, result)?; | ||
self.stmt += 1; | ||
Ok(()) | ||
} | ||
fn terminator(&mut self) -> EvalResult<()> { | ||
self.stmt = 0; | ||
let term = { | ||
let block_data = self.mir.basic_block_data(self.block); | ||
let terminator = block_data.terminator(); | ||
let result = self.fncx.eval_terminator(terminator); | ||
self.fncx.maybe_report(terminator.span, result)? | ||
}; | ||
match term { | ||
TerminatorTarget::Block(block) => { | ||
self.block = block; | ||
}, | ||
TerminatorTarget::Return => { | ||
self.fncx.pop_stack_frame(); | ||
self.fncx.name_stack.pop(); | ||
if !self.fncx.stack.is_empty() { | ||
self.block = self.fncx.frame().next_block; | ||
self.mir = self.fncx.mir(); | ||
} | ||
}, | ||
TerminatorTarget::Call => { | ||
self.block = self.fncx.frame().next_block; | ||
self.mir = self.fncx.mir(); | ||
}, | ||
} | ||
Ok(()) | ||
} | ||
pub fn step<'step>(&'step mut self) -> EvalResult<Event<'step, 'tcx>> { | ||
(self.process)(self)?; | ||
|
||
if self.fncx.stack.is_empty() { | ||
// fuse the iterator | ||
self.process = Self::dummy; | ||
return Ok(Event::Done); | ||
} | ||
|
||
let basic_block = self.mir.basic_block_data(self.block); | ||
|
||
if let Some(stmt) = basic_block.statements.get(self.stmt) { | ||
self.process = Self::statement; | ||
return Ok(Event::Assignment(&stmt)); | ||
} | ||
|
||
self.process = Self::terminator; | ||
Ok(Event::Terminator(basic_block.terminator())) | ||
} | ||
pub fn block(&self) -> mir::BasicBlock { | ||
self.block | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,8 @@ use error::{EvalError, EvalResult}; | |
use memory::{Memory, Pointer}; | ||
use primval::{self, PrimVal}; | ||
|
||
mod iterator; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This module name/filename is confusing given that it has no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
struct GlobalEvalContext<'a, 'tcx: 'a> { | ||
/// The results of the type checker, from rustc. | ||
tcx: TyCtxt<'a, 'tcx, 'tcx>, | ||
|
@@ -135,6 +137,23 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { | |
name_stack: Vec::new(), | ||
} | ||
} | ||
|
||
fn call(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult<Option<Pointer>> { | ||
let mut nested_fecx = FnEvalContext::new(self); | ||
|
||
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); | ||
nested_fecx.run()?; | ||
Ok(return_ptr) | ||
} | ||
} | ||
|
||
impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { | ||
|
@@ -167,55 +186,22 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { | |
} | ||
|
||
fn run(&mut self) -> EvalResult<()> { | ||
'outer: while !self.stack.is_empty() { | ||
let mut current_block = self.frame().next_block; | ||
let mut stepper = iterator::Stepper::new(self); | ||
'outer: loop { | ||
use self::iterator::Event::*; | ||
trace!("// {:?}", stepper.block()); | ||
|
||
loop { | ||
trace!("// {:?}", current_block); | ||
let current_mir = self.mir().clone(); // Cloning a reference. | ||
let block_data = current_mir.basic_block_data(current_block); | ||
|
||
for stmt in &block_data.statements { | ||
trace!("{:?}", stmt); | ||
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; | ||
let result = self.eval_assignment(lvalue, rvalue); | ||
self.maybe_report(stmt.span, result)?; | ||
} | ||
|
||
let terminator = block_data.terminator(); | ||
trace!("{:?}", terminator.kind); | ||
|
||
let result = self.eval_terminator(terminator); | ||
match self.maybe_report(terminator.span, result)? { | ||
TerminatorTarget::Block(block) => current_block = block, | ||
TerminatorTarget::Return => { | ||
self.pop_stack_frame(); | ||
self.name_stack.pop(); | ||
match stepper.step()? { | ||
Assignment(statement) => trace!("{:?}", statement), | ||
Terminator(terminator) => { | ||
trace!("{:?}", terminator.kind); | ||
continue 'outer; | ||
} | ||
TerminatorTarget::Call => continue 'outer, | ||
}, | ||
Done => return Ok(()), | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
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); | ||
nested_fecx.run()?; | ||
Ok(return_ptr) | ||
} | ||
|
||
fn push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, | ||
|
@@ -996,13 +982,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { | |
use rustc::mir::repr::Literal::*; | ||
match *literal { | ||
Value { ref value } => Ok(self.const_to_ptr(value)?), | ||
Item { .. } => unimplemented!(), | ||
Item { .. } => Err(EvalError::Unimplemented(format!("function pointers are unimplemented"))), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea it can be more than that... but most of it is tagged with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be happy with EDIT: wording There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
Promoted { index } => { | ||
// TODO(solson): Mark constants and statics as read-only and cache their | ||
// values. | ||
let current_mir = self.mir(); | ||
let mir = ¤t_mir.promoted[index]; | ||
self.call_nested(mir).map(Option::unwrap) | ||
self.gecx.call(mir).map(Option::unwrap) | ||
} | ||
} | ||
} | ||
|
@@ -1021,7 +1007,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { | |
Static(def_id) => { | ||
// TODO(solson): Mark constants and statics as read-only and cache their values. | ||
let mir = self.load_mir(def_id); | ||
self.call_nested(&mir)?.unwrap() | ||
self.gecx.call(&mir)?.unwrap() | ||
} | ||
|
||
Projection(ref proj) => { | ||
|
@@ -1426,10 +1412,9 @@ pub fn interpret_start_points<'a, 'tcx>( | |
debug!("Interpreting: {}", item.name); | ||
|
||
let mut gecx = GlobalEvalContext::new(tcx, mir_map); | ||
let mut fecx = FnEvalContext::new(&mut gecx); | ||
match fecx.call_nested(mir) { | ||
match gecx.call(mir) { | ||
Ok(Some(return_ptr)) => if log_enabled!(::log::LogLevel::Debug) { | ||
fecx.memory.dump(return_ptr.alloc_id); | ||
gecx.memory.dump(return_ptr.alloc_id); | ||
}, | ||
Ok(None) => warn!("diverging function returned"), | ||
Err(_e) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
filling_drop, | ||
question_mark, | ||
rustc_private, | ||
pub_restricted, | ||
)] | ||
|
||
// From rustc. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#![feature(custom_attribute)] | ||
#![allow(dead_code, unused_attributes)] | ||
|
||
//error-pattern:function pointers are unimplemented | ||
|
||
static mut X: usize = 5; | ||
|
||
#[miri_run] | ||
fn static_mut() { | ||
unsafe { | ||
X = 6; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So yeah, this might fail for a different reason in the future (mutation of a static), but I'm fine with having it here so we notice when that happens. Although it would be allowed in versions of Miri not intended for rustc const eval. |
||
assert_eq!(X, 6); | ||
} | ||
} | ||
|
||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: blank lines between functions