From e73fa7733de466136d56dc8e184a176c9188e3f4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 31 May 2016 18:26:03 +0200 Subject: [PATCH 01/33] can't evaluate failed assertions yet --- src/interpreter.rs | 2 +- tests/compile-fail/unimplemented.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/unimplemented.rs diff --git a/src/interpreter.rs b/src/interpreter.rs index 0f9cc899193d6..0b004c78e4f9d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -996,7 +996,7 @@ 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"))), Promoted { index } => { // TODO(solson): Mark constants and statics as read-only and cache their // values. diff --git a/tests/compile-fail/unimplemented.rs b/tests/compile-fail/unimplemented.rs new file mode 100644 index 0000000000000..010883b7d617f --- /dev/null +++ b/tests/compile-fail/unimplemented.rs @@ -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; + assert_eq!(X, 6); + } +} + +fn main() {} From 8398781132ae6d9062178db4f206e0262fc1013d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 14:33:37 +0200 Subject: [PATCH 02/33] remove one layer of indirection when interpreting const/static/main functions --- src/interpreter.rs | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 0b004c78e4f9d..bd51e2d2dbf14 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -135,6 +135,23 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { name_stack: Vec::new(), } } + + fn call(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult> { + 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> { @@ -201,23 +218,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(()) } - fn call_nested(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult> { - 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>, return_ptr: Option) { @@ -1002,7 +1002,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { // 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 +1021,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 +1426,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) => { From 5a8b0ab5798704fce6ae7fe8fd7073bd48fd244b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 13:55:16 +0200 Subject: [PATCH 03/33] don't clone the MIR Rc in every iteration --- src/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index bd51e2d2dbf14..c8e6d0bbe1f2b 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -186,10 +186,10 @@ 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 current_mir = self.mir(); 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 { From 2405c81c65586df5c65ae8670151b5237edf4398 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 17:05:20 +0200 Subject: [PATCH 04/33] stepwise interpretation --- src/interpreter/iterator.rs | 92 ++++++++++++++++++++++ src/{interpreter.rs => interpreter/mod.rs} | 38 +++------ src/lib.rs | 1 + 3 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 src/interpreter/iterator.rs rename src/{interpreter.rs => interpreter/mod.rs} (98%) diff --git a/src/interpreter/iterator.rs b/src/interpreter/iterator.rs new file mode 100644 index 0000000000000..7793c0df28215 --- /dev/null +++ b/src/interpreter/iterator.rs @@ -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> { + (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 + } +} diff --git a/src/interpreter.rs b/src/interpreter/mod.rs similarity index 98% rename from src/interpreter.rs rename to src/interpreter/mod.rs index c8e6d0bbe1f2b..8b93edd888c6c 100644 --- a/src/interpreter.rs +++ b/src/interpreter/mod.rs @@ -20,6 +20,8 @@ use error::{EvalError, EvalResult}; use memory::{Memory, Pointer}; use primval::{self, PrimVal}; +mod iterator; + struct GlobalEvalContext<'a, 'tcx: 'a> { /// The results of the type checker, from rustc. tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -184,38 +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 current_mir = self.mir(); + let mut stepper = iterator::Stepper::new(self); + 'outer: loop { + use self::iterator::Event::*; + trace!("// {:?}", stepper.block()); loop { - trace!("// {:?}", current_block); - 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 push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index 80d89c164ac5f..4e06a3ce38d56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ filling_drop, question_mark, rustc_private, + pub_restricted, )] // From rustc. From 77e1ec2b4995358ce4b02683dd491653a23a97b1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 19:01:40 +0200 Subject: [PATCH 05/33] style: spaces between functions --- src/interpreter/iterator.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/interpreter/iterator.rs b/src/interpreter/iterator.rs index 7793c0df28215..4c8d0c7292b4f 100644 --- a/src/interpreter/iterator.rs +++ b/src/interpreter/iterator.rs @@ -30,7 +30,9 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx 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]; @@ -40,6 +42,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.stmt += 1; Ok(()) } + fn terminator(&mut self) -> EvalResult<()> { self.stmt = 0; let term = { @@ -67,6 +70,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } Ok(()) } + pub fn step<'step>(&'step mut self) -> EvalResult> { (self.process)(self)?; @@ -86,6 +90,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.process = Self::terminator; Ok(Event::Terminator(basic_block.terminator())) } + pub fn block(&self) -> mir::BasicBlock { self.block } From 0c269a500cae8fce43dcd1a01dcf1b9654e6757f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 19:17:18 +0200 Subject: [PATCH 06/33] rename `iterator` module to `stepper` --- src/interpreter/mod.rs | 6 +++--- src/interpreter/{iterator.rs => stepper.rs} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename src/interpreter/{iterator.rs => stepper.rs} (100%) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8b93edd888c6c..a7dedc9ddc65b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -20,7 +20,7 @@ use error::{EvalError, EvalResult}; use memory::{Memory, Pointer}; use primval::{self, PrimVal}; -mod iterator; +mod stepper; struct GlobalEvalContext<'a, 'tcx: 'a> { /// The results of the type checker, from rustc. @@ -186,9 +186,9 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } fn run(&mut self) -> EvalResult<()> { - let mut stepper = iterator::Stepper::new(self); + let mut stepper = stepper::Stepper::new(self); 'outer: loop { - use self::iterator::Event::*; + use self::stepper::Event::*; trace!("// {:?}", stepper.block()); loop { diff --git a/src/interpreter/iterator.rs b/src/interpreter/stepper.rs similarity index 100% rename from src/interpreter/iterator.rs rename to src/interpreter/stepper.rs From 52111783771d9e967a63995b3e2d7c6538fc6b52 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 19:20:23 +0200 Subject: [PATCH 07/33] note that not all literal items are function pointers --- src/interpreter/mod.rs | 2 +- tests/compile-fail/unimplemented.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a7dedc9ddc65b..5592783d86329 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -982,7 +982,7 @@ 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 { .. } => Err(EvalError::Unimplemented(format!("function pointers are unimplemented"))), + Item { .. } => Err(EvalError::Unimplemented(format!("literal items (e.g. mentions of function items) are unimplemented"))), Promoted { index } => { // TODO(solson): Mark constants and statics as read-only and cache their // values. diff --git a/tests/compile-fail/unimplemented.rs b/tests/compile-fail/unimplemented.rs index 010883b7d617f..3b99fda9477dc 100644 --- a/tests/compile-fail/unimplemented.rs +++ b/tests/compile-fail/unimplemented.rs @@ -1,7 +1,7 @@ #![feature(custom_attribute)] #![allow(dead_code, unused_attributes)] -//error-pattern:function pointers are unimplemented +//error-pattern:literal items (e.g. mentions of function items) are unimplemented static mut X: usize = 5; From 6ac64f19af6280d58d68118f09fd65950fb4aa6b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Jun 2016 17:05:17 +0200 Subject: [PATCH 08/33] also step through promoteds, constants and statics --- src/interpreter/mod.rs | 42 +++++---- src/interpreter/stepper.rs | 136 +++++++++++++++++++++++++--- tests/compile-fail/unimplemented.rs | 10 +- tests/run-pass/bug.rs | 14 +++ 4 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 tests/run-pass/bug.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 5592783d86329..ec830fd008f88 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -20,6 +20,8 @@ use error::{EvalError, EvalResult}; use memory::{Memory, Pointer}; use primval::{self, PrimVal}; +use std::collections::HashMap; + mod stepper; struct GlobalEvalContext<'a, 'tcx: 'a> { @@ -45,6 +47,9 @@ struct GlobalEvalContext<'a, 'tcx: 'a> { /// * Function DefIds and Substs to print proper substituted function names. /// * Spans pointing to specific function calls in the source. name_stack: Vec<(DefId, &'tcx Substs<'tcx>, codemap::Span)>, + + /// Precomputed statics and constants + statics: DefIdMap, } struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> { @@ -88,6 +93,9 @@ struct Frame<'a, 'tcx: 'a> { /// The offset of the first temporary in `self.locals`. temp_offset: usize, + + /// List of precomputed promoted constants + promoted: HashMap, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -122,6 +130,13 @@ enum TerminatorTarget { Return, } +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +enum ConstantId { + Promoted { index: usize }, + Static { def_id: DefId }, +} + + impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { GlobalEvalContext { @@ -135,10 +150,11 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { .expect("Session::target::uint_type was usize")/8), substs_stack: Vec::new(), name_stack: Vec::new(), + statics: DefIdMap(), } } - fn call(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult> { + fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { let mut nested_fecx = FnEvalContext::new(self); let return_ptr = match mir.return_ty { @@ -150,6 +166,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { }; let substs = nested_fecx.substs(); + nested_fecx.name_stack.push((def_id, substs, mir.span)); nested_fecx.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr); nested_fecx.run()?; Ok(return_ptr) @@ -193,9 +210,9 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { loop { match stepper.step()? { - Assignment(statement) => trace!("{:?}", statement), - Terminator(terminator) => { - trace!("{:?}", terminator.kind); + Assignment => trace!("{:?}", stepper.stmt()), + Terminator => { + trace!("{:?}", stepper.term().kind); continue 'outer; }, Done => return Ok(()), @@ -230,6 +247,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { locals: locals, var_offset: num_args, temp_offset: num_args + num_vars, + promoted: HashMap::new(), }); } @@ -983,13 +1001,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { match *literal { Value { ref value } => Ok(self.const_to_ptr(value)?), Item { .. } => Err(EvalError::Unimplemented(format!("literal items (e.g. mentions of function items) are unimplemented"))), - 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.gecx.call(mir).map(Option::unwrap) - } + Promoted { index } => Ok(*self.frame().promoted.get(&index).expect("a promoted constant hasn't been precomputed")), } } } @@ -1004,11 +1016,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Var(i) => self.frame().locals[self.frame().var_offset + i as usize], Temp(i) => self.frame().locals[self.frame().temp_offset + i as usize], - Static(def_id) => { - // TODO(solson): Mark constants and statics as read-only and cache their values. - let mir = self.load_mir(def_id); - self.gecx.call(&mir)?.unwrap() - } + Static(def_id) => *self.gecx.statics.get(&def_id).expect("static should have been cached"), Projection(ref proj) => { let base = self.eval_lvalue(&proj.base)?; @@ -1412,7 +1420,7 @@ pub fn interpret_start_points<'a, 'tcx>( debug!("Interpreting: {}", item.name); let mut gecx = GlobalEvalContext::new(tcx, mir_map); - match gecx.call(mir) { + match gecx.call(mir, tcx.map.local_def_id(id)) { Ok(Some(return_ptr)) => if log_enabled!(::log::LogLevel::Debug) { gecx.memory.dump(return_ptr.alloc_id); }, diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 4c8d0c7292b4f..0543b40c8f5c3 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -2,49 +2,61 @@ use super::{ FnEvalContext, CachedMir, TerminatorTarget, + ConstantId, }; use error::EvalResult; use rustc::mir::repr as mir; +use rustc::ty::{self, subst}; +use rustc::mir::visit::Visitor; +use syntax::codemap::Span; +use memory::Pointer; +use std::rc::Rc; -pub enum Event<'a, 'tcx: 'a> { - Assignment(&'a mir::Statement<'tcx>), - Terminator(&'a mir::Terminator<'tcx>), +pub enum Event { + Assignment, + Terminator, 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, + // a stack of statement positions + stmt: Vec, mir: CachedMir<'mir, 'tcx>, process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, + // a stack of constants + constants: Vec>, } 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 { + let mut stepper = Stepper { block: fncx.frame().next_block, mir: fncx.mir(), fncx: fncx, - stmt: 0, + stmt: vec![0], process: Self::dummy, - } + constants: Vec::new(), + }; + stepper.extract_constants(); + stepper } 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 stmt = &block_data.statements[*self.stmt.last().unwrap()]; 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; + *self.stmt.last_mut().unwrap() += 1; Ok(()) } fn terminator(&mut self) -> EvalResult<()> { - self.stmt = 0; + *self.stmt.last_mut().unwrap() = 0; let term = { let block_data = self.mir.basic_block_data(self.block); let terminator = block_data.terminator(); @@ -58,6 +70,9 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx TerminatorTarget::Return => { self.fncx.pop_stack_frame(); self.fncx.name_stack.pop(); + self.stmt.pop(); + assert!(self.constants.last().unwrap().is_empty()); + self.constants.pop(); if !self.fncx.stack.is_empty() { self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); @@ -66,12 +81,24 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx TerminatorTarget::Call => { self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); + self.stmt.push(0); + self.extract_constants(); }, } Ok(()) } - pub fn step<'step>(&'step mut self) -> EvalResult> { + fn alloc(&mut self, ty: ty::FnOutput<'tcx>) -> Pointer { + match ty { + ty::FnConverging(ty) => { + let size = self.fncx.type_size(ty); + self.fncx.memory.allocate(size) + } + ty::FnDiverging => panic!("there's no such thing as an unreachable static"), + } + } + + pub fn step(&mut self) -> EvalResult { (self.process)(self)?; if self.fncx.stack.is_empty() { @@ -80,18 +107,97 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx return Ok(Event::Done); } + match self.constants.last_mut().unwrap().pop() { + Some((ConstantId::Promoted { index }, span)) => { + trace!("adding promoted constant {}", index); + let mir = self.mir.promoted[index].clone(); + let return_ptr = self.alloc(mir.return_ty); + self.fncx.frame_mut().promoted.insert(index, return_ptr); + let substs = self.fncx.substs(); + // FIXME: somehow encode that this is a promoted constant's frame + println!("{}, {}, {}", self.fncx.stack.len(), self.fncx.name_stack.len(), self.fncx.substs_stack.len()); + let def_id = self.fncx.name_stack.last().unwrap().0; + self.fncx.name_stack.push((def_id, substs, span)); + self.fncx.push_stack_frame(CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr)); + self.stmt.push(0); + self.constants.push(Vec::new()); + self.block = self.fncx.frame().next_block; + self.mir = self.fncx.mir(); + }, + Some((ConstantId::Static { def_id }, span)) => { + trace!("adding static {:?}", def_id); + let mir = self.fncx.load_mir(def_id); + let return_ptr = self.alloc(mir.return_ty); + self.fncx.gecx.statics.insert(def_id, return_ptr); + let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); + self.fncx.name_stack.push((def_id, substs, span)); + self.fncx.push_stack_frame(mir, substs, Some(return_ptr)); + self.stmt.push(0); + self.constants.push(Vec::new()); + self.block = self.fncx.frame().next_block; + self.mir = self.fncx.mir(); + }, + None => {}, + } + let basic_block = self.mir.basic_block_data(self.block); - if let Some(stmt) = basic_block.statements.get(self.stmt) { + if basic_block.statements.len() > *self.stmt.last().unwrap() { self.process = Self::statement; - return Ok(Event::Assignment(&stmt)); + return Ok(Event::Assignment); } self.process = Self::terminator; - Ok(Event::Terminator(basic_block.terminator())) + Ok(Event::Terminator) } - + + /// returns the basic block index of the currently processed block pub fn block(&self) -> mir::BasicBlock { self.block } + + /// returns the statement that will be processed next + pub fn stmt(&self) -> &mir::Statement { + let block_data = self.mir.basic_block_data(self.block); + &block_data.statements[*self.stmt.last().unwrap()] + } + + /// returns the terminator of the current block + pub fn term(&self) -> &mir::Terminator { + let block_data = self.mir.basic_block_data(self.block); + block_data.terminator() + } + + fn extract_constants(&mut self) { + let mut extractor = ConstantExtractor { + constants: Vec::new(), + }; + extractor.visit_mir(&self.mir); + self.constants.push(extractor.constants); + } +} + +struct ConstantExtractor { + constants: Vec<(ConstantId, Span)>, +} + +impl<'tcx> Visitor<'tcx> for ConstantExtractor { + fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) { + self.super_constant(constant); + match constant.literal { + // already computed by rustc + mir::Literal::Value { .. } => {} + mir::Literal::Item { .. } => {}, // FIXME: unimplemented + mir::Literal::Promoted { index } => { + self.constants.push((ConstantId::Promoted { index: index }, constant.span)); + } + } + } + + fn visit_statement(&mut self, block: mir::BasicBlock, stmt: &mir::Statement<'tcx>) { + self.super_statement(block, stmt); + if let mir::StatementKind::Assign(mir::Lvalue::Static(def_id), _) = stmt.kind { + self.constants.push((ConstantId::Static { def_id: def_id }, stmt.span)); + } + } } diff --git a/tests/compile-fail/unimplemented.rs b/tests/compile-fail/unimplemented.rs index 3b99fda9477dc..7ff4b1c191c13 100644 --- a/tests/compile-fail/unimplemented.rs +++ b/tests/compile-fail/unimplemented.rs @@ -1,16 +1,12 @@ #![feature(custom_attribute)] #![allow(dead_code, unused_attributes)] -//error-pattern:literal items (e.g. mentions of function items) are unimplemented +//error-pattern:static should have been cached -static mut X: usize = 5; #[miri_run] -fn static_mut() { - unsafe { - X = 6; - assert_eq!(X, 6); - } +fn failed_assertions() { + assert_eq!(5, 6); } fn main() {} diff --git a/tests/run-pass/bug.rs b/tests/run-pass/bug.rs new file mode 100644 index 0000000000000..3006da2c163de --- /dev/null +++ b/tests/run-pass/bug.rs @@ -0,0 +1,14 @@ +#![feature(custom_attribute)] +#![allow(dead_code, unused_attributes)] + +static mut X: usize = 5; + +#[miri_run] +fn static_mut() { + unsafe { + X = 6; + assert_eq!(X, 6); + } +} + +fn main() {} From 97bc1d4beeb510415856c1d878d390d6c050ba57 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Jun 2016 17:36:05 +0200 Subject: [PATCH 09/33] add a const fn test --- tests/run-pass/calls.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/calls.rs b/tests/run-pass/calls.rs index be975320bba93..ba68fb44a6c39 100644 --- a/tests/run-pass/calls.rs +++ b/tests/run-pass/calls.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute)] +#![feature(custom_attribute, const_fn)] #![allow(dead_code, unused_attributes)] #[miri_run] @@ -33,6 +33,15 @@ fn cross_crate_fn_call() -> i64 { if 1i32.is_positive() { 1 } else { 0 } } +const fn foo(i: i64) -> i64 { *&i + 1 } + +#[miri_run] +fn const_fn_call() -> i64 { + let x = 5 + foo(5); + assert_eq!(x, 11); + x +} + #[miri_run] fn main() { assert_eq!(call(), 2); From 38ae3526e56137d10a6c0e21d861016d6de0c698 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Jun 2016 18:03:22 +0200 Subject: [PATCH 10/33] remove a debug message that snuck into the commit --- src/interpreter/stepper.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 0543b40c8f5c3..e341a9efd8a4b 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -115,7 +115,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.fncx.frame_mut().promoted.insert(index, return_ptr); let substs = self.fncx.substs(); // FIXME: somehow encode that this is a promoted constant's frame - println!("{}, {}, {}", self.fncx.stack.len(), self.fncx.name_stack.len(), self.fncx.substs_stack.len()); let def_id = self.fncx.name_stack.last().unwrap().0; self.fncx.name_stack.push((def_id, substs, span)); self.fncx.push_stack_frame(CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr)); From 05f829cc9f2627c14f93bf70540311390d36f043 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Jun 2016 18:21:32 +0200 Subject: [PATCH 11/33] merge the three stacks in the interpreter --- src/interpreter/mod.rs | 58 ++++++++++++++++++-------------------- src/interpreter/stepper.rs | 9 ++---- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index ec830fd008f88..7ae20f78dc480 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -37,17 +37,6 @@ struct GlobalEvalContext<'a, 'tcx: 'a> { /// The virtual memory system. memory: Memory, - /// 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. - substs_stack: Vec<&'tcx Substs<'tcx>>, - - // TODO(solson): Merge with `substs_stack`. Also try restructuring `Frame` to accomodate. - /// A stack of the things necessary to print good strack traces: - /// * Function DefIds and Substs to print proper substituted function names. - /// * Spans pointing to specific function calls in the source. - name_stack: Vec<(DefId, &'tcx Substs<'tcx>, codemap::Span)>, - /// Precomputed statics and constants statics: DefIdMap, } @@ -74,6 +63,15 @@ impl<'a, 'b, 'mir, 'tcx> DerefMut for FnEvalContext<'a, 'b, 'mir, 'tcx> { /// A stack frame. struct Frame<'a, 'tcx: 'a> { + /// The def_id of the current function + def_id: DefId, + + /// The span of the call site + span: codemap::Span, + + /// type substitutions for the current function invocation + substs: &'tcx Substs<'tcx>, + /// The MIR for the function called on this frame. mir: CachedMir<'a, 'tcx>, @@ -148,15 +146,16 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { .uint_type .bit_width() .expect("Session::target::uint_type was usize")/8), - substs_stack: Vec::new(), - name_stack: Vec::new(), statics: DefIdMap(), } } fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { + let substs = self.tcx.mk_substs(subst::Substs::empty()); + let mut nested_fecx = FnEvalContext::new(self); + nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); let return_ptr = match mir.return_ty { ty::FnConverging(ty) => { let size = nested_fecx.type_size(ty); @@ -164,10 +163,8 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } ty::FnDiverging => None, }; + nested_fecx.frame_mut().return_ptr = return_ptr; - let substs = nested_fecx.substs(); - nested_fecx.name_stack.push((def_id, substs, mir.span)); - nested_fecx.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr); nested_fecx.run()?; Ok(return_ptr) } @@ -184,7 +181,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn maybe_report(&self, span: codemap::Span, r: EvalResult) -> EvalResult { if let Err(ref e) = r { let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); - for &(def_id, substs, span) in self.name_stack.iter().rev() { + for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() { // FIXME(solson): Find a way to do this without this Display impl hack. use rustc::util::ppaux; use std::fmt; @@ -221,20 +218,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } - fn push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, + fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, return_ptr: Option) { - self.substs_stack.push(substs); - let arg_tys = mir.arg_decls.iter().map(|a| a.ty); let var_tys = mir.var_decls.iter().map(|v| v.ty); let temp_tys = mir.temp_decls.iter().map(|t| t.ty); - let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { - let size = self.type_size(ty); - self.memory.allocate(size) - }).collect(); - let num_args = mir.arg_decls.len(); let num_vars = mir.var_decls.len(); @@ -244,18 +234,27 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { mir: mir.clone(), next_block: mir::START_BLOCK, return_ptr: return_ptr, - locals: locals, + locals: Vec::new(), var_offset: num_args, temp_offset: num_args + num_vars, promoted: HashMap::new(), + span: span, + def_id: def_id, + substs: substs, }); + + let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { + let size = self.type_size(ty); + self.memory.allocate(size) + }).collect(); + + self.frame_mut().locals = locals; } fn pop_stack_frame(&mut self) { ::log_settings::settings().indentation -= 1; let _frame = self.stack.pop().expect("tried to pop a stack frame, but there were none"); // TODO(solson): Deallocate local variables. - self.substs_stack.pop(); } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) @@ -382,8 +381,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } let mir = self.load_mir(resolved_def_id); - self.name_stack.push((def_id, substs, terminator.span)); - self.push_stack_frame(mir, resolved_substs, return_ptr); + self.push_stack_frame(def_id, terminator.span, mir, resolved_substs, return_ptr); for (i, (src, src_ty)) in arg_srcs.into_iter().enumerate() { let dest = self.frame().locals[i]; @@ -1237,7 +1235,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } fn substs(&self) -> &'tcx Substs<'tcx> { - self.substs_stack.last().cloned().unwrap_or_else(|| self.tcx.mk_substs(Substs::empty())) + self.frame().substs } fn load_mir(&self, def_id: DefId) -> CachedMir<'mir, 'tcx> { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index e341a9efd8a4b..48773d6e0df75 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -69,7 +69,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx }, TerminatorTarget::Return => { self.fncx.pop_stack_frame(); - self.fncx.name_stack.pop(); self.stmt.pop(); assert!(self.constants.last().unwrap().is_empty()); self.constants.pop(); @@ -115,9 +114,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.fncx.frame_mut().promoted.insert(index, return_ptr); let substs = self.fncx.substs(); // FIXME: somehow encode that this is a promoted constant's frame - let def_id = self.fncx.name_stack.last().unwrap().0; - self.fncx.name_stack.push((def_id, substs, span)); - self.fncx.push_stack_frame(CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr)); + let def_id = self.fncx.frame().def_id; + self.fncx.push_stack_frame(def_id, span, CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); self.block = self.fncx.frame().next_block; @@ -129,8 +127,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let return_ptr = self.alloc(mir.return_ty); self.fncx.gecx.statics.insert(def_id, return_ptr); let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); - self.fncx.name_stack.push((def_id, substs, span)); - self.fncx.push_stack_frame(mir, substs, Some(return_ptr)); + self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); self.block = self.fncx.frame().next_block; From cc1ca73f5736a4aaa7a1ae164788051b8366fa3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 15:48:56 +0200 Subject: [PATCH 12/33] jit interpretation of constants --- src/interpreter/mod.rs | 34 ++++-- src/interpreter/stepper.rs | 165 ++++++++++++++++++---------- tests/compile-fail/unimplemented.rs | 2 +- tests/run-pass/constants.rs | 11 ++ 4 files changed, 139 insertions(+), 73 deletions(-) create mode 100644 tests/run-pass/constants.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 7ae20f78dc480..7e59b2674e87f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -129,9 +129,9 @@ enum TerminatorTarget { } #[derive(Clone, Debug, Eq, PartialEq, Hash)] -enum ConstantId { +enum ConstantId<'tcx> { Promoted { index: usize }, - Static { def_id: DefId }, + Static { def_id: DefId, substs: &'tcx Substs<'tcx> }, } @@ -156,13 +156,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { let mut nested_fecx = FnEvalContext::new(self); nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); - 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 return_ptr = nested_fecx.alloc_ret_ptr(mir.return_ty); nested_fecx.frame_mut().return_ptr = return_ptr; nested_fecx.run()?; @@ -178,6 +172,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } + fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>) -> Option { + match ty { + ty::FnConverging(ty) => { + let size = self.type_size(ty); + Some(self.memory.allocate(size)) + } + ty::FnDiverging => None, + } + } + fn maybe_report(&self, span: codemap::Span, r: EvalResult) -> EvalResult { if let Err(ref e) = r { let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); @@ -207,6 +211,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { loop { match stepper.step()? { + Constant => trace!("next statement requires the computation of a constant"), Assignment => trace!("{:?}", stepper.stmt()), Terminator => { trace!("{:?}", stepper.term().kind); @@ -998,7 +1003,14 @@ 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 { .. } => Err(EvalError::Unimplemented(format!("literal items (e.g. mentions of function items) are unimplemented"))), + Item { def_id, substs } => { + let item_ty = self.tcx.lookup_item_type(def_id).subst(self.tcx, substs); + if item_ty.ty.is_fn() { + Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string())) + } else { + Ok(*self.statics.get(&def_id).expect("static should have been cached (rvalue)")) + } + }, Promoted { index } => Ok(*self.frame().promoted.get(&index).expect("a promoted constant hasn't been precomputed")), } } @@ -1014,7 +1026,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Var(i) => self.frame().locals[self.frame().var_offset + i as usize], Temp(i) => self.frame().locals[self.frame().temp_offset + i as usize], - Static(def_id) => *self.gecx.statics.get(&def_id).expect("static should have been cached"), + Static(def_id) => *self.gecx.statics.get(&def_id).expect("static should have been cached (lvalue)"), Projection(ref proj) => { let base = self.eval_lvalue(&proj.base)?; diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 48773d6e0df75..b84680f733783 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -6,13 +6,15 @@ use super::{ }; use error::EvalResult; use rustc::mir::repr as mir; -use rustc::ty::{self, subst}; -use rustc::mir::visit::Visitor; +use rustc::ty::subst::{self, Subst}; +use rustc::hir::def_id::DefId; +use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use memory::Pointer; use std::rc::Rc; pub enum Event { + Constant, Assignment, Terminator, Done, @@ -26,21 +28,19 @@ pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ mir: CachedMir<'mir, 'tcx>, process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, // a stack of constants - constants: Vec>, + constants: Vec, Span, Pointer, CachedMir<'mir, 'tcx>)>>, } 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 { - let mut stepper = Stepper { + Stepper { block: fncx.frame().next_block, mir: fncx.mir(), fncx: fncx, stmt: vec![0], process: Self::dummy, - constants: Vec::new(), - }; - stepper.extract_constants(); - stepper + constants: vec![Vec::new()], + } } fn dummy(&mut self) -> EvalResult<()> { Ok(()) } @@ -81,70 +81,86 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); self.stmt.push(0); - self.extract_constants(); + self.constants.push(Vec::new()); }, } Ok(()) } - fn alloc(&mut self, ty: ty::FnOutput<'tcx>) -> Pointer { - match ty { - ty::FnConverging(ty) => { - let size = self.fncx.type_size(ty); - self.fncx.memory.allocate(size) - } - ty::FnDiverging => panic!("there's no such thing as an unreachable static"), - } - } - - pub fn step(&mut self) -> EvalResult { - (self.process)(self)?; - - if self.fncx.stack.is_empty() { - // fuse the iterator - self.process = Self::dummy; - return Ok(Event::Done); - } - + fn constant(&mut self) -> EvalResult<()> { match self.constants.last_mut().unwrap().pop() { - Some((ConstantId::Promoted { index }, span)) => { - trace!("adding promoted constant {}", index); - let mir = self.mir.promoted[index].clone(); - let return_ptr = self.alloc(mir.return_ty); - self.fncx.frame_mut().promoted.insert(index, return_ptr); + Some((ConstantId::Promoted { index }, span, return_ptr, mir)) => { + trace!("adding promoted constant {}, {:?}", index, span); let substs = self.fncx.substs(); // FIXME: somehow encode that this is a promoted constant's frame let def_id = self.fncx.frame().def_id; - self.fncx.push_stack_frame(def_id, span, CachedMir::Owned(Rc::new(mir)), substs, Some(return_ptr)); + self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); }, - Some((ConstantId::Static { def_id }, span)) => { - trace!("adding static {:?}", def_id); - let mir = self.fncx.load_mir(def_id); - let return_ptr = self.alloc(mir.return_ty); + Some((ConstantId::Static { def_id, substs }, span, return_ptr, mir)) => { + trace!("adding static {:?}, {:?}", def_id, span); self.fncx.gecx.statics.insert(def_id, return_ptr); - let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); }, - None => {}, + None => unreachable!(), + } + Ok(()) + } + + pub fn step(&mut self) -> EvalResult { + (self.process)(self)?; + + if self.fncx.stack.is_empty() { + // fuse the iterator + self.process = Self::dummy; + return Ok(Event::Done); + } + + if !self.constants.last().unwrap().is_empty() { + self.process = Self::constant; + return Ok(Event::Constant); } let basic_block = self.mir.basic_block_data(self.block); - if basic_block.statements.len() > *self.stmt.last().unwrap() { - self.process = Self::statement; - return Ok(Event::Assignment); + if let Some(ref stmt) = basic_block.statements.get(*self.stmt.last().unwrap()) { + assert!(self.constants.last().unwrap().is_empty()); + ConstantExtractor { + constants: &mut self.constants.last_mut().unwrap(), + span: stmt.span, + fncx: self.fncx, + mir: &self.mir, + }.visit_statement(self.block, stmt); + if self.constants.last().unwrap().is_empty() { + self.process = Self::statement; + return Ok(Event::Assignment); + } else { + self.process = Self::constant; + return Ok(Event::Constant); + } } - self.process = Self::terminator; - Ok(Event::Terminator) + let terminator = basic_block.terminator(); + ConstantExtractor { + constants: &mut self.constants.last_mut().unwrap(), + span: terminator.span, + fncx: self.fncx, + mir: &self.mir, + }.visit_terminator(self.block, terminator); + if self.constants.last().unwrap().is_empty() { + self.process = Self::terminator; + Ok(Event::Terminator) + } else { + self.process = Self::constant; + return Ok(Event::Constant); + } } /// returns the basic block index of the currently processed block @@ -163,37 +179,64 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let block_data = self.mir.basic_block_data(self.block); block_data.terminator() } +} - fn extract_constants(&mut self) { - let mut extractor = ConstantExtractor { - constants: Vec::new(), - }; - extractor.visit_mir(&self.mir); - self.constants.push(extractor.constants); - } +struct ConstantExtractor<'a: 'c, 'b: 'a + 'mir + 'c, 'c, 'mir: 'c, 'tcx: 'a + 'b + 'c> { + constants: &'c mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>, + span: Span, + mir: &'c mir::Mir<'tcx>, + fncx: &'c mut FnEvalContext<'a, 'b, 'mir, 'tcx>, } -struct ConstantExtractor { - constants: Vec<(ConstantId, Span)>, +impl<'a, 'b, 'c, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { + fn constant(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { + if self.fncx.gecx.statics.contains_key(&def_id) { + return; + } + let cid = ConstantId::Static { + def_id: def_id, + substs: substs, + }; + let mir = self.fncx.load_mir(def_id); + let ptr = self.fncx.alloc_ret_ptr(mir.return_ty).expect("there's no such thing as an unreachable static"); + self.constants.push((cid, span, ptr, mir)); + } } -impl<'tcx> Visitor<'tcx> for ConstantExtractor { +impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) { self.super_constant(constant); match constant.literal { // already computed by rustc mir::Literal::Value { .. } => {} - mir::Literal::Item { .. } => {}, // FIXME: unimplemented + mir::Literal::Item { def_id, substs } => { + let item_ty = self.fncx.tcx.lookup_item_type(def_id).subst(self.fncx.tcx, substs); + if item_ty.ty.is_fn() { + // unimplemented + } else { + self.constant(def_id, substs, constant.span); + } + }, mir::Literal::Promoted { index } => { - self.constants.push((ConstantId::Promoted { index: index }, constant.span)); + if self.fncx.frame().promoted.contains_key(&index) { + return; + } + let mir = self.mir.promoted[index].clone(); + let return_ty = mir.return_ty; + let return_ptr = self.fncx.alloc_ret_ptr(return_ty).expect("there's no such thing as an unreachable static"); + self.fncx.frame_mut().promoted.insert(index, return_ptr); + let mir = CachedMir::Owned(Rc::new(mir)); + self.constants.push((ConstantId::Promoted { index: index }, constant.span, return_ptr, mir)); } } } - fn visit_statement(&mut self, block: mir::BasicBlock, stmt: &mir::Statement<'tcx>) { - self.super_statement(block, stmt); - if let mir::StatementKind::Assign(mir::Lvalue::Static(def_id), _) = stmt.kind { - self.constants.push((ConstantId::Static { def_id: def_id }, stmt.span)); + fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) { + self.super_lvalue(lvalue, context); + if let mir::Lvalue::Static(def_id) = *lvalue { + let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); + let span = self.span; + self.constant(def_id, substs, span); } } } diff --git a/tests/compile-fail/unimplemented.rs b/tests/compile-fail/unimplemented.rs index 7ff4b1c191c13..754d3d9ee7e6d 100644 --- a/tests/compile-fail/unimplemented.rs +++ b/tests/compile-fail/unimplemented.rs @@ -1,7 +1,7 @@ #![feature(custom_attribute)] #![allow(dead_code, unused_attributes)] -//error-pattern:static should have been cached +//error-pattern:unimplemented: mentions of function items #[miri_run] diff --git a/tests/run-pass/constants.rs b/tests/run-pass/constants.rs new file mode 100644 index 0000000000000..3d6b08c340df5 --- /dev/null +++ b/tests/run-pass/constants.rs @@ -0,0 +1,11 @@ +#![feature(custom_attribute)] +#![allow(dead_code, unused_attributes)] + +const A: usize = *&5; + +#[miri_run] +fn foo() -> usize { + A +} + +fn main() {} From f995db9ffba925590e4c78917362998be02fcbc1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 16:51:51 +0200 Subject: [PATCH 13/33] store the current block in the frame --- src/interpreter/mod.rs | 28 +++++++++++++++++++++------- src/interpreter/stepper.rs | 36 +++++++++++++----------------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 7e59b2674e87f..f20a958cd0e76 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -118,8 +118,8 @@ enum CachedMir<'mir, 'tcx: 'mir> { /// Represents the action to be taken in the main loop as a result of executing a terminator. enum TerminatorTarget { - /// Make a local jump to the given block. - Block(mir::BasicBlock), + /// Make a local jump to the next block + Block, /// Start executing from the new current frame. (For function calls.) Call, @@ -268,12 +268,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let target = match terminator.kind { Return => TerminatorTarget::Return, - Goto { target } => TerminatorTarget::Block(target), + Goto { target } => { + self.frame_mut().next_block = target; + TerminatorTarget::Block + }, If { ref cond, targets: (then_target, else_target) } => { let cond_ptr = self.eval_operand(cond)?; let cond_val = self.memory.read_bool(cond_ptr)?; - TerminatorTarget::Block(if cond_val { then_target } else { else_target }) + self.frame_mut().next_block = if cond_val { then_target } else { else_target }; + TerminatorTarget::Block } SwitchInt { ref discr, ref values, ref targets, .. } => { @@ -296,7 +300,8 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } - TerminatorTarget::Block(target_block) + self.frame_mut().next_block = target_block; + TerminatorTarget::Block } Switch { ref discr, ref targets, adt_def } => { @@ -307,7 +312,10 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { .position(|v| discr_val == v.disr_val.to_u64_unchecked()); match matching { - Some(i) => TerminatorTarget::Block(targets[i]), + Some(i) => { + self.frame_mut().next_block = targets[i]; + TerminatorTarget::Block + }, None => return Err(EvalError::InvalidDiscriminant), } } @@ -408,7 +416,8 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let ptr = self.eval_lvalue(value)?.to_ptr(); let ty = self.lvalue_ty(value); self.drop(ptr, ty)?; - TerminatorTarget::Block(target) + self.frame_mut().next_block = target; + TerminatorTarget::Block } Resume => unimplemented!(), @@ -1238,6 +1247,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.stack.last().expect("no call frames exist") } + fn basic_block(&self) -> &mir::BasicBlockData<'tcx> { + let frame = self.frame(); + frame.mir.basic_block_data(frame.next_block) + } + fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> { self.stack.last_mut().expect("no call frames exist") } diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index b84680f733783..4a0dedf8a0f9e 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -22,7 +22,6 @@ pub enum Event { pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, - block: mir::BasicBlock, // a stack of statement positions stmt: Vec, mir: CachedMir<'mir, 'tcx>, @@ -34,7 +33,6 @@ pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ 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: vec![0], @@ -46,7 +44,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn dummy(&mut self) -> EvalResult<()> { Ok(()) } fn statement(&mut self) -> EvalResult<()> { - let block_data = self.mir.basic_block_data(self.block); + let block_data = self.mir.basic_block_data(self.fncx.frame().next_block); let stmt = &block_data.statements[*self.stmt.last().unwrap()]; let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; let result = self.fncx.eval_assignment(lvalue, rvalue); @@ -58,27 +56,23 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn terminator(&mut self) -> EvalResult<()> { *self.stmt.last_mut().unwrap() = 0; let term = { - let block_data = self.mir.basic_block_data(self.block); + let block_data = self.mir.basic_block_data(self.fncx.frame().next_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::Block => {}, TerminatorTarget::Return => { self.fncx.pop_stack_frame(); self.stmt.pop(); assert!(self.constants.last().unwrap().is_empty()); self.constants.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(); self.stmt.push(0); self.constants.push(Vec::new()); @@ -97,7 +91,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); - self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); }, Some((ConstantId::Static { def_id, substs }, span, return_ptr, mir)) => { @@ -106,7 +99,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); self.stmt.push(0); self.constants.push(Vec::new()); - self.block = self.fncx.frame().next_block; self.mir = self.fncx.mir(); }, None => unreachable!(), @@ -128,7 +120,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx return Ok(Event::Constant); } - let basic_block = self.mir.basic_block_data(self.block); + let block = self.fncx.frame().next_block; + let basic_block = self.mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(*self.stmt.last().unwrap()) { assert!(self.constants.last().unwrap().is_empty()); @@ -137,7 +130,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx span: stmt.span, fncx: self.fncx, mir: &self.mir, - }.visit_statement(self.block, stmt); + }.visit_statement(block, stmt); if self.constants.last().unwrap().is_empty() { self.process = Self::statement; return Ok(Event::Assignment); @@ -153,7 +146,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx span: terminator.span, fncx: self.fncx, mir: &self.mir, - }.visit_terminator(self.block, terminator); + }.visit_terminator(block, terminator); if self.constants.last().unwrap().is_empty() { self.process = Self::terminator; Ok(Event::Terminator) @@ -163,21 +156,18 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } } - /// returns the basic block index of the currently processed block - pub fn block(&self) -> mir::BasicBlock { - self.block - } - /// returns the statement that will be processed next pub fn stmt(&self) -> &mir::Statement { - let block_data = self.mir.basic_block_data(self.block); - &block_data.statements[*self.stmt.last().unwrap()] + &self.fncx.basic_block().statements[*self.stmt.last().unwrap()] } /// returns the terminator of the current block pub fn term(&self) -> &mir::Terminator { - let block_data = self.mir.basic_block_data(self.block); - block_data.terminator() + self.fncx.basic_block().terminator() + } + + pub fn block(&self) -> mir::BasicBlock { + self.fncx.frame().next_block } } From 346560b31809e2ca5459eb221f093fd0ab1abea1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 16:57:47 +0200 Subject: [PATCH 14/33] factor out the statement index into the stackframe --- src/interpreter/mod.rs | 4 ++++ src/interpreter/stepper.rs | 19 +++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index f20a958cd0e76..079ed6cf59af9 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -94,6 +94,9 @@ struct Frame<'a, 'tcx: 'a> { /// List of precomputed promoted constants promoted: HashMap, + + /// The index of the currently evaluated statment + stmt: usize, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -246,6 +249,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { span: span, def_id: def_id, substs: substs, + stmt: 0, }); let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 4a0dedf8a0f9e..448fa83fa6766 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -22,8 +22,6 @@ pub enum Event { pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, - // a stack of statement positions - stmt: Vec, mir: CachedMir<'mir, 'tcx>, process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, // a stack of constants @@ -35,7 +33,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Stepper { mir: fncx.mir(), fncx: fncx, - stmt: vec![0], process: Self::dummy, constants: vec![Vec::new()], } @@ -45,16 +42,17 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn statement(&mut self) -> EvalResult<()> { let block_data = self.mir.basic_block_data(self.fncx.frame().next_block); - let stmt = &block_data.statements[*self.stmt.last().unwrap()]; + let stmt = &block_data.statements[self.fncx.frame().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.last_mut().unwrap() += 1; + self.fncx.frame_mut().stmt += 1; Ok(()) } fn terminator(&mut self) -> EvalResult<()> { - *self.stmt.last_mut().unwrap() = 0; + // after a terminator we go to a new block + self.fncx.frame_mut().stmt = 0; let term = { let block_data = self.mir.basic_block_data(self.fncx.frame().next_block); let terminator = block_data.terminator(); @@ -65,7 +63,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx TerminatorTarget::Block => {}, TerminatorTarget::Return => { self.fncx.pop_stack_frame(); - self.stmt.pop(); assert!(self.constants.last().unwrap().is_empty()); self.constants.pop(); if !self.fncx.stack.is_empty() { @@ -74,7 +71,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx }, TerminatorTarget::Call => { self.mir = self.fncx.mir(); - self.stmt.push(0); self.constants.push(Vec::new()); }, } @@ -89,7 +85,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx // FIXME: somehow encode that this is a promoted constant's frame let def_id = self.fncx.frame().def_id; self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.stmt.push(0); self.constants.push(Vec::new()); self.mir = self.fncx.mir(); }, @@ -97,7 +92,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx trace!("adding static {:?}, {:?}", def_id, span); self.fncx.gecx.statics.insert(def_id, return_ptr); self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.stmt.push(0); self.constants.push(Vec::new()); self.mir = self.fncx.mir(); }, @@ -121,9 +115,10 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } let block = self.fncx.frame().next_block; + let stmt = self.fncx.frame().stmt; let basic_block = self.mir.basic_block_data(block); - if let Some(ref stmt) = basic_block.statements.get(*self.stmt.last().unwrap()) { + if let Some(ref stmt) = basic_block.statements.get(stmt) { assert!(self.constants.last().unwrap().is_empty()); ConstantExtractor { constants: &mut self.constants.last_mut().unwrap(), @@ -158,7 +153,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx /// returns the statement that will be processed next pub fn stmt(&self) -> &mir::Statement { - &self.fncx.basic_block().statements[*self.stmt.last().unwrap()] + &self.fncx.basic_block().statements[self.fncx.frame().stmt] } /// returns the terminator of the current block From 02eed64cc0c0fdd992713c5b5b1dfdd3813e09bf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 17:04:08 +0200 Subject: [PATCH 15/33] update documentation --- src/interpreter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 079ed6cf59af9..d97ad5d476283 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -75,7 +75,7 @@ struct Frame<'a, 'tcx: 'a> { /// The MIR for the function called on this frame. mir: CachedMir<'a, 'tcx>, - /// The block this frame will execute when a function call returns back to this frame. + /// The block that is currently executed (or will be executed after the above call stacks return) next_block: mir::BasicBlock, /// A pointer for writing the return value of the current call if it's not a diverging call. From 4743842821ffa91546af7806e18f71821ff8f2da Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 17:08:51 +0200 Subject: [PATCH 16/33] move constants stack to stackframe --- src/interpreter/mod.rs | 6 +++++- src/interpreter/stepper.rs | 26 ++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index d97ad5d476283..9701e1157a4f6 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -14,7 +14,7 @@ use std::rc::Rc; use std::{iter, mem}; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, DUMMY_SP}; +use syntax::codemap::{self, DUMMY_SP, Span}; use error::{EvalError, EvalResult}; use memory::{Memory, Pointer}; @@ -97,6 +97,9 @@ struct Frame<'a, 'tcx: 'a> { /// The index of the currently evaluated statment 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)] @@ -250,6 +253,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { def_id: def_id, substs: substs, stmt: 0, + constants: Vec::new(), }); let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 448fa83fa6766..8abc7830f5182 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -24,8 +24,6 @@ pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, mir: CachedMir<'mir, 'tcx>, process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>, - // a stack of constants - constants: Vec, Span, Pointer, CachedMir<'mir, 'tcx>)>>, } impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> { @@ -34,7 +32,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: fncx.mir(), fncx: fncx, process: Self::dummy, - constants: vec![Vec::new()], } } @@ -62,37 +59,33 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx match term { TerminatorTarget::Block => {}, TerminatorTarget::Return => { + assert!(self.fncx.frame().constants.is_empty()); self.fncx.pop_stack_frame(); - assert!(self.constants.last().unwrap().is_empty()); - self.constants.pop(); if !self.fncx.stack.is_empty() { self.mir = self.fncx.mir(); } }, TerminatorTarget::Call => { self.mir = self.fncx.mir(); - self.constants.push(Vec::new()); }, } Ok(()) } fn constant(&mut self) -> EvalResult<()> { - match self.constants.last_mut().unwrap().pop() { + match self.fncx.frame_mut().constants.pop() { Some((ConstantId::Promoted { index }, span, return_ptr, mir)) => { trace!("adding promoted constant {}, {:?}", index, span); let substs = self.fncx.substs(); // FIXME: somehow encode that this is a promoted constant's frame let def_id = self.fncx.frame().def_id; self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.constants.push(Vec::new()); self.mir = self.fncx.mir(); }, Some((ConstantId::Static { def_id, substs }, span, return_ptr, mir)) => { trace!("adding static {:?}, {:?}", def_id, span); self.fncx.gecx.statics.insert(def_id, return_ptr); self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.constants.push(Vec::new()); self.mir = self.fncx.mir(); }, None => unreachable!(), @@ -109,7 +102,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx return Ok(Event::Done); } - if !self.constants.last().unwrap().is_empty() { + if !self.fncx.frame().constants.is_empty() { self.process = Self::constant; return Ok(Event::Constant); } @@ -119,14 +112,13 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let basic_block = self.mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { - assert!(self.constants.last().unwrap().is_empty()); + assert!(self.fncx.frame().constants.is_empty()); ConstantExtractor { - constants: &mut self.constants.last_mut().unwrap(), span: stmt.span, fncx: self.fncx, mir: &self.mir, }.visit_statement(block, stmt); - if self.constants.last().unwrap().is_empty() { + if self.fncx.frame().constants.is_empty() { self.process = Self::statement; return Ok(Event::Assignment); } else { @@ -137,12 +129,11 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let terminator = basic_block.terminator(); ConstantExtractor { - constants: &mut self.constants.last_mut().unwrap(), span: terminator.span, fncx: self.fncx, mir: &self.mir, }.visit_terminator(block, terminator); - if self.constants.last().unwrap().is_empty() { + if self.fncx.frame().constants.is_empty() { self.process = Self::terminator; Ok(Event::Terminator) } else { @@ -167,7 +158,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } struct ConstantExtractor<'a: 'c, 'b: 'a + 'mir + 'c, 'c, 'mir: 'c, 'tcx: 'a + 'b + 'c> { - constants: &'c mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>, span: Span, mir: &'c mir::Mir<'tcx>, fncx: &'c mut FnEvalContext<'a, 'b, 'mir, 'tcx>, @@ -184,7 +174,7 @@ impl<'a, 'b, 'c, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { }; let mir = self.fncx.load_mir(def_id); let ptr = self.fncx.alloc_ret_ptr(mir.return_ty).expect("there's no such thing as an unreachable static"); - self.constants.push((cid, span, ptr, mir)); + self.fncx.frame_mut().constants.push((cid, span, ptr, mir)); } } @@ -211,7 +201,7 @@ impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mi let return_ptr = self.fncx.alloc_ret_ptr(return_ty).expect("there's no such thing as an unreachable static"); self.fncx.frame_mut().promoted.insert(index, return_ptr); let mir = CachedMir::Owned(Rc::new(mir)); - self.constants.push((ConstantId::Promoted { index: index }, constant.span, return_ptr, mir)); + self.fncx.frame_mut().constants.push((ConstantId::Promoted { index: index }, constant.span, return_ptr, mir)); } } } From dc85b1142111401f33a797fc449d8e36291f4444 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 17:14:36 +0200 Subject: [PATCH 17/33] stop producing executable files in the root folder during benchmarks... --- benches/miri_helper.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benches/miri_helper.rs b/benches/miri_helper.rs index 54c15a27ed884..e085373a36dc0 100644 --- a/benches/miri_helper.rs +++ b/benches/miri_helper.rs @@ -10,7 +10,7 @@ extern crate test; use self::miri::interpreter; use self::rustc::session::Session; -use self::rustc_driver::{driver, CompilerCalls}; +use self::rustc_driver::{driver, CompilerCalls, Compilation}; use std::cell::RefCell; use std::rc::Rc; use std::env::var; @@ -35,6 +35,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { let bencher = self.0.clone(); + control.after_analysis.stop = Compilation::Stop; control.after_analysis.callback = Box::new(move |state| { state.session.abort_if_errors(); bencher.borrow_mut().iter(|| { From 4c833a54d2ff4e180d8d2e9dd81274ad9c8cc367 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 3 Jun 2016 17:41:36 +0200 Subject: [PATCH 18/33] globally cache statics and promoteds --- src/interpreter/mod.rs | 48 +++++++++++++++++++++++++++++--------- src/interpreter/stepper.rs | 47 ++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 9701e1157a4f6..1b8be7bebd62d 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -37,8 +37,8 @@ struct GlobalEvalContext<'a, 'tcx: 'a> { /// The virtual memory system. memory: Memory, - /// Precomputed statics and constants - statics: DefIdMap, + /// Precomputed statics, constants and promoteds + statics: HashMap, Pointer>, } struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> { @@ -92,9 +92,6 @@ struct Frame<'a, 'tcx: 'a> { /// The offset of the first temporary in `self.locals`. temp_offset: usize, - /// List of precomputed promoted constants - promoted: HashMap, - /// The index of the currently evaluated statment stmt: usize, @@ -136,10 +133,28 @@ enum TerminatorTarget { #[derive(Clone, Debug, Eq, PartialEq, Hash)] enum ConstantId<'tcx> { - Promoted { index: usize }, + Promoted { def_id: DefId, substs: &'tcx Substs<'tcx>, index: usize }, Static { def_id: DefId, substs: &'tcx Substs<'tcx> }, } +impl<'tcx> ConstantId<'tcx> { + fn substs(&self) -> &'tcx Substs<'tcx> { + use self::ConstantId::*; + match *self { + Promoted { substs, .. } | + Static { substs, .. } => substs + } + } + + fn def_id(&self) -> DefId { + use self::ConstantId::*; + match *self { + Promoted { def_id, .. } | + Static { def_id, .. } => def_id, + } + } +} + impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { @@ -152,7 +167,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { .uint_type .bit_width() .expect("Session::target::uint_type was usize")/8), - statics: DefIdMap(), + statics: HashMap::new(), } } @@ -248,7 +263,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { locals: Vec::new(), var_offset: num_args, temp_offset: num_args + num_vars, - promoted: HashMap::new(), span: span, def_id: def_id, substs: substs, @@ -1025,10 +1039,18 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { if item_ty.ty.is_fn() { Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string())) } else { - Ok(*self.statics.get(&def_id).expect("static should have been cached (rvalue)")) + let cid = ConstantId::Static{ def_id: def_id, substs: substs }; + Ok(*self.statics.get(&cid).expect("static should have been cached (rvalue)")) } }, - Promoted { index } => Ok(*self.frame().promoted.get(&index).expect("a promoted constant hasn't been precomputed")), + Promoted { index } => { + let cid = ConstantId::Promoted { + def_id: self.frame().def_id, + substs: self.substs(), + index: index, + }; + Ok(*self.statics.get(&cid).expect("a promoted constant hasn't been precomputed")) + }, } } } @@ -1043,7 +1065,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Var(i) => self.frame().locals[self.frame().var_offset + i as usize], Temp(i) => self.frame().locals[self.frame().temp_offset + i as usize], - Static(def_id) => *self.gecx.statics.get(&def_id).expect("static should have been cached (lvalue)"), + Static(def_id) => { + let substs = self.tcx.mk_substs(subst::Substs::empty()); + let cid = ConstantId::Static{ def_id: def_id, substs: substs }; + *self.gecx.statics.get(&cid).expect("static should have been cached (lvalue)") + }, Projection(ref proj) => { let base = self.eval_lvalue(&proj.base)?; diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 8abc7830f5182..1a2fbe43408a0 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -10,7 +10,6 @@ use rustc::ty::subst::{self, Subst}; use rustc::hir::def_id::DefId; use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; -use memory::Pointer; use std::rc::Rc; pub enum Event { @@ -73,23 +72,11 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } fn constant(&mut self) -> EvalResult<()> { - match self.fncx.frame_mut().constants.pop() { - Some((ConstantId::Promoted { index }, span, return_ptr, mir)) => { - trace!("adding promoted constant {}, {:?}", index, span); - let substs = self.fncx.substs(); - // FIXME: somehow encode that this is a promoted constant's frame - let def_id = self.fncx.frame().def_id; - self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.mir = self.fncx.mir(); - }, - Some((ConstantId::Static { def_id, substs }, span, return_ptr, mir)) => { - trace!("adding static {:?}, {:?}", def_id, span); - self.fncx.gecx.statics.insert(def_id, return_ptr); - self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.mir = self.fncx.mir(); - }, - None => unreachable!(), - } + 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)); + self.mir = self.fncx.mir(); Ok(()) } @@ -164,16 +151,17 @@ struct ConstantExtractor<'a: 'c, 'b: 'a + 'mir + 'c, 'c, 'mir: 'c, 'tcx: 'a + 'b } impl<'a, 'b, 'c, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { - fn constant(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { - if self.fncx.gecx.statics.contains_key(&def_id) { - return; - } + fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { let cid = ConstantId::Static { def_id: def_id, substs: substs, }; + if self.fncx.gecx.statics.contains_key(&cid) { + return; + } let mir = self.fncx.load_mir(def_id); let ptr = self.fncx.alloc_ret_ptr(mir.return_ty).expect("there's no such thing as an unreachable static"); + self.fncx.statics.insert(cid.clone(), ptr); self.fncx.frame_mut().constants.push((cid, span, ptr, mir)); } } @@ -189,19 +177,24 @@ impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mi if item_ty.ty.is_fn() { // unimplemented } else { - self.constant(def_id, substs, constant.span); + self.static_item(def_id, substs, constant.span); } }, mir::Literal::Promoted { index } => { - if self.fncx.frame().promoted.contains_key(&index) { + let cid = ConstantId::Promoted { + def_id: self.fncx.frame().def_id, + substs: self.fncx.substs(), + index: index, + }; + if self.fncx.statics.contains_key(&cid) { return; } let mir = self.mir.promoted[index].clone(); let return_ty = mir.return_ty; let return_ptr = self.fncx.alloc_ret_ptr(return_ty).expect("there's no such thing as an unreachable static"); - self.fncx.frame_mut().promoted.insert(index, return_ptr); let mir = CachedMir::Owned(Rc::new(mir)); - self.fncx.frame_mut().constants.push((ConstantId::Promoted { index: index }, constant.span, return_ptr, mir)); + self.fncx.statics.insert(cid.clone(), return_ptr); + self.fncx.frame_mut().constants.push((cid, constant.span, return_ptr, mir)); } } } @@ -211,7 +204,7 @@ impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mi if let mir::Lvalue::Static(def_id) = *lvalue { let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); let span = self.span; - self.constant(def_id, substs, span); + self.static_item(def_id, substs, span); } } } From 4d44a970a39d4bd6ec517b3958e180def9040e3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 09:38:59 +0200 Subject: [PATCH 19/33] move some methods from FnEvalContext to GlobalEvalContext --- src/interpreter/mod.rs | 256 +++++++++++++++++++++++++---------------- 1 file changed, 160 insertions(+), 96 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 1b8be7bebd62d..5072270f1aa7b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -173,16 +173,150 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult> { let substs = self.tcx.mk_substs(subst::Substs::empty()); + let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs); let mut nested_fecx = FnEvalContext::new(self); nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None); - let return_ptr = nested_fecx.alloc_ret_ptr(mir.return_ty); + nested_fecx.frame_mut().return_ptr = return_ptr; nested_fecx.run()?; Ok(return_ptr) } + + fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { + match ty { + ty::FnConverging(ty) => { + let size = self.type_size(ty, substs); + Some(self.memory.allocate(size)) + } + ty::FnDiverging => None, + } + } + // TODO(solson): Try making const_to_primval instead. + fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult { + use rustc::middle::const_val::ConstVal::*; + match *const_val { + Float(_f) => unimplemented!(), + Integral(int) => { + // TODO(solson): Check int constant type. + let ptr = self.memory.allocate(8); + self.memory.write_uint(ptr, int.to_u64_unchecked(), 8)?; + Ok(ptr) + } + Str(ref s) => { + let psize = self.memory.pointer_size; + let static_ptr = self.memory.allocate(s.len()); + let ptr = self.memory.allocate(psize * 2); + self.memory.write_bytes(static_ptr, s.as_bytes())?; + self.memory.write_ptr(ptr, static_ptr)?; + self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?; + Ok(ptr) + } + ByteStr(ref bs) => { + let psize = self.memory.pointer_size; + let static_ptr = self.memory.allocate(bs.len()); + let ptr = self.memory.allocate(psize); + self.memory.write_bytes(static_ptr, bs)?; + self.memory.write_ptr(ptr, static_ptr)?; + Ok(ptr) + } + Bool(b) => { + let ptr = self.memory.allocate(1); + self.memory.write_bool(ptr, b)?; + Ok(ptr) + } + Char(_c) => unimplemented!(), + Struct(_node_id) => unimplemented!(), + Tuple(_node_id) => unimplemented!(), + Function(_def_id) => unimplemented!(), + Array(_, _) => unimplemented!(), + Repeat(_, _) => unimplemented!(), + Dummy => unimplemented!(), + } + } + + fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { + self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment()) + } + + fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { + ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP) + } + + fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> { + // Do the initial selection for the obligation. This yields the shallow result we are + // looking for -- that is, what specific impl. + self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| { + let mut selcx = traits::SelectionContext::new(&infcx); + + let obligation = traits::Obligation::new( + traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), + trait_ref.to_poly_trait_predicate(), + ); + let selection = selcx.select(&obligation).unwrap().unwrap(); + + // Currently, we use a fulfillment context to completely resolve all nested obligations. + // This is because they can inform the inference of the impl's type parameters. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable) + }) + } + + /// Trait method, which has to be resolved to an impl method. + pub fn trait_method( + &self, + def_id: DefId, + substs: &'tcx Substs<'tcx> + ) -> (DefId, &'tcx Substs<'tcx>) { + let method_item = self.tcx.impl_or_trait_item(def_id); + let trait_id = method_item.container().id(); + let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id)); + match self.fulfill_obligation(trait_ref) { + traits::VtableImpl(vtable_impl) => { + let impl_did = vtable_impl.impl_def_id; + let mname = self.tcx.item_name(def_id); + // Create a concatenated set of substitutions which includes those from the impl + // and those from the method: + let impl_substs = vtable_impl.substs.with_method_from(substs); + let substs = self.tcx.mk_substs(impl_substs); + let mth = get_impl_method(self.tcx, impl_did, substs, mname); + + (mth.method.def_id, mth.substs) + } + + traits::VtableClosure(vtable_closure) => + (vtable_closure.closure_def_id, vtable_closure.substs.func_substs), + + traits::VtableFnPointer(_fn_ty) => { + let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap(); + unimplemented!() + // let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty); + + // let method_ty = def_ty(tcx, def_id, substs); + // let fn_ptr_ty = match method_ty.sty { + // ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)), + // _ => unreachable!("expected fn item type, found {}", + // method_ty) + // }; + // Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) + } + + traits::VtableObject(ref _data) => { + unimplemented!() + // Callee { + // data: Virtual(traits::get_vtable_index_of_object_method( + // tcx, data, def_id)), + // ty: def_ty(tcx, def_id, substs) + // } + } + vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable), + } + } } impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { @@ -193,33 +327,36 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } - fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>) -> Option { - match ty { - ty::FnConverging(ty) => { - let size = self.type_size(ty); - Some(self.memory.allocate(size)) + #[inline(never)] + #[cold] + fn report(&self, e: &EvalError) { + let stmt = self.frame().stmt; + let block = self.basic_block(); + let span = if stmt < block.statements.len() { + block.statements[stmt].span + } else { + block.terminator().span + }; + let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); + for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() { + // FIXME(solson): Find a way to do this without this Display impl hack. + use rustc::util::ppaux; + use std::fmt; + struct Instance<'tcx>(DefId, &'tcx Substs<'tcx>); + impl<'tcx> fmt::Display for Instance<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[], + |tcx| tcx.lookup_item_type(self.0).generics) + } } - ty::FnDiverging => None, + err.span_note(span, &format!("inside call to {}", Instance(def_id, substs))); } + err.emit(); } - fn maybe_report(&self, span: codemap::Span, r: EvalResult) -> EvalResult { + fn maybe_report(&self, r: EvalResult) -> EvalResult { if let Err(ref e) = r { - let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() { - // FIXME(solson): Find a way to do this without this Display impl hack. - use rustc::util::ppaux; - use std::fmt; - struct Instance<'tcx>(DefId, &'tcx Substs<'tcx>); - impl<'tcx> fmt::Display for Instance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[], - |tcx| tcx.lookup_item_type(self.0).generics) - } - } - err.span_note(span, &format!("inside call to {}", Instance(def_id, substs))); - } - err.emit(); + self.report(e); } r } @@ -1317,79 +1454,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } } - - fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> { - // Do the initial selection for the obligation. This yields the shallow result we are - // looking for -- that is, what specific impl. - self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| { - let mut selcx = traits::SelectionContext::new(&infcx); - - let obligation = traits::Obligation::new( - traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), - trait_ref.to_poly_trait_predicate(), - ); - let selection = selcx.select(&obligation).unwrap().unwrap(); - - // Currently, we use a fulfillment context to completely resolve all nested obligations. - // This is because they can inform the inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable) - }) - } - - /// Trait method, which has to be resolved to an impl method. - pub fn trait_method( - &self, - def_id: DefId, - substs: &'tcx Substs<'tcx> - ) -> (DefId, &'tcx Substs<'tcx>) { - let method_item = self.tcx.impl_or_trait_item(def_id); - let trait_id = method_item.container().id(); - let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id)); - match self.fulfill_obligation(trait_ref) { - traits::VtableImpl(vtable_impl) => { - let impl_did = vtable_impl.impl_def_id; - let mname = self.tcx.item_name(def_id); - // Create a concatenated set of substitutions which includes those from the impl - // and those from the method: - let impl_substs = vtable_impl.substs.with_method_from(substs); - let substs = self.tcx.mk_substs(impl_substs); - let mth = get_impl_method(self.tcx, impl_did, substs, mname); - - (mth.method.def_id, mth.substs) - } - - traits::VtableClosure(vtable_closure) => - (vtable_closure.closure_def_id, vtable_closure.substs.func_substs), - - traits::VtableFnPointer(_fn_ty) => { - let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - unimplemented!() - // let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty); - - // let method_ty = def_ty(tcx, def_id, substs); - // let fn_ptr_ty = match method_ty.sty { - // ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)), - // _ => unreachable!("expected fn item type, found {}", - // method_ty) - // }; - // Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) - } - - traits::VtableObject(ref _data) => { - unimplemented!() - // Callee { - // data: Virtual(traits::get_vtable_index_of_object_method( - // tcx, data, def_id)), - // ty: def_ty(tcx, def_id, substs) - // } - } - vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable), - } - } } fn pointee_type(ptr_ty: ty::Ty) -> Option { From f42be6db54660b73f814e6083a87005e799d5666 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 6 Jun 2016 15:22:33 +0200 Subject: [PATCH 20/33] move load_mir to the global eval context --- src/interpreter/mod.rs | 44 +++++++++++++++++-------------------- src/interpreter/stepper.rs | 45 +++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 5072270f1aa7b..22db69a2afff8 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -317,6 +317,26 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable), } } + + fn load_mir(&self, def_id: DefId) -> CachedMir<'a, '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 => { + let mut mir_cache = self.mir_cache.borrow_mut(); + if let Some(mir) = mir_cache.get(&def_id) { + return CachedMir::Owned(mir.clone()); + } + + let cs = &self.tcx.sess.cstore; + let mir = cs.maybe_get_item_mir(self.tcx, def_id).unwrap_or_else(|| { + panic!("no mir for {:?}", def_id); + }); + let cached = Rc::new(mir); + mir_cache.insert(def_id, cached.clone()); + CachedMir::Owned(cached) + } + } + } } impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { @@ -1430,30 +1450,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn mir(&self) -> CachedMir<'mir, 'tcx> { self.frame().mir.clone() } - - fn substs(&self) -> &'tcx Substs<'tcx> { - self.frame().substs - } - - 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 => { - let mut mir_cache = self.mir_cache.borrow_mut(); - if let Some(mir) = mir_cache.get(&def_id) { - return CachedMir::Owned(mir.clone()); - } - - let cs = &self.tcx.sess.cstore; - let mir = cs.maybe_get_item_mir(self.tcx, def_id).unwrap_or_else(|| { - panic!("no mir for {:?}", def_id); - }); - let cached = Rc::new(mir); - mir_cache.insert(def_id, cached.clone()); - CachedMir::Owned(cached) - } - } - } } fn pointee_type(ptr_ty: ty::Ty) -> Option { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 1a2fbe43408a0..6fb287228be88 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -3,6 +3,7 @@ use super::{ CachedMir, TerminatorTarget, ConstantId, + GlobalEvalContext }; use error::EvalResult; use rustc::mir::repr as mir; @@ -102,8 +103,9 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx assert!(self.fncx.frame().constants.is_empty()); ConstantExtractor { span: stmt.span, - fncx: self.fncx, mir: &self.mir, + gecx: self.fncx.gecx, + frame: self.fncx.stack.last_mut().expect("stack empty"), }.visit_statement(block, stmt); if self.fncx.frame().constants.is_empty() { self.process = Self::statement; @@ -115,10 +117,12 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } let terminator = basic_block.terminator(); + assert!(self.fncx.frame().constants.is_empty()); ConstantExtractor { span: terminator.span, - fncx: self.fncx, mir: &self.mir, + gecx: self.fncx.gecx, + frame: self.fncx.stack.last_mut().expect("stack empty"), }.visit_terminator(block, terminator); if self.fncx.frame().constants.is_empty() { self.process = Self::terminator; @@ -144,36 +148,37 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } } -struct ConstantExtractor<'a: 'c, 'b: 'a + 'mir + 'c, 'c, 'mir: 'c, 'tcx: 'a + 'b + 'c> { +struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { span: Span, - mir: &'c mir::Mir<'tcx>, - fncx: &'c mut FnEvalContext<'a, 'b, 'mir, 'tcx>, + mir: &'a CachedMir<'mir, 'tcx>, + frame: &'a mut Frame<'mir, 'tcx>, + gecx: &'a mut GlobalEvalContext<'b, 'tcx>, } -impl<'a, 'b, 'c, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { +impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { let cid = ConstantId::Static { def_id: def_id, substs: substs, }; - if self.fncx.gecx.statics.contains_key(&cid) { + if self.gecx.statics.contains_key(&cid) { return; } - let mir = self.fncx.load_mir(def_id); - let ptr = self.fncx.alloc_ret_ptr(mir.return_ty).expect("there's no such thing as an unreachable static"); - self.fncx.statics.insert(cid.clone(), ptr); - self.fncx.frame_mut().constants.push((cid, span, ptr, mir)); + 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"); + self.gecx.statics.insert(cid.clone(), ptr); + self.frame.constants.push((cid, span, ptr, mir)); } } -impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> { +impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> { fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) { self.super_constant(constant); match constant.literal { // already computed by rustc mir::Literal::Value { .. } => {} mir::Literal::Item { def_id, substs } => { - let item_ty = self.fncx.tcx.lookup_item_type(def_id).subst(self.fncx.tcx, substs); + let item_ty = self.gecx.tcx.lookup_item_type(def_id).subst(self.gecx.tcx, substs); if item_ty.ty.is_fn() { // unimplemented } else { @@ -182,19 +187,19 @@ impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mi }, mir::Literal::Promoted { index } => { let cid = ConstantId::Promoted { - def_id: self.fncx.frame().def_id, - substs: self.fncx.substs(), + def_id: self.frame.def_id, + substs: self.frame.substs, index: index, }; - if self.fncx.statics.contains_key(&cid) { + if self.gecx.statics.contains_key(&cid) { return; } let mir = self.mir.promoted[index].clone(); let return_ty = mir.return_ty; - let return_ptr = self.fncx.alloc_ret_ptr(return_ty).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)); - self.fncx.statics.insert(cid.clone(), return_ptr); - self.fncx.frame_mut().constants.push((cid, constant.span, return_ptr, mir)); + self.gecx.statics.insert(cid.clone(), return_ptr); + self.frame.constants.push((cid, constant.span, return_ptr, mir)); } } } @@ -202,7 +207,7 @@ impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mi fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) { self.super_lvalue(lvalue, context); if let mir::Lvalue::Static(def_id) = *lvalue { - let substs = self.fncx.tcx.mk_substs(subst::Substs::empty()); + let substs = self.gecx.tcx.mk_substs(subst::Substs::empty()); let span = self.span; self.static_item(def_id, substs, span); } From c881cf10d86deca32093eb40319a24a793de7d0b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 6 Jun 2016 15:24:56 +0200 Subject: [PATCH 21/33] clippy nits --- src/interpreter/stepper.rs | 2 +- src/memory.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 6fb287228be88..f733d1d46c838 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -129,7 +129,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Ok(Event::Terminator) } else { self.process = Self::constant; - return Ok(Event::Constant); + Ok(Event::Constant) } } diff --git a/src/memory.rs b/src/memory.rs index 728d5310f8611..ab527a47c0bf5 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -88,7 +88,7 @@ impl Memory { alloc.bytes.extend(iter::repeat(0).take(amount)); alloc.undef_mask.grow(amount, false); } else if size > new_size { - return Err(EvalError::Unimplemented(format!("unimplemented allocation relocation"))); + return Err(EvalError::Unimplemented(format!("unimplemented allocation relocation (from {} to {})", size, new_size))); // alloc.bytes.truncate(new_size); // alloc.undef_mask.len = new_size; // TODO: potentially remove relocations From 1f27d3f7b3816fde346c5140801c7dd5ced3f823 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 10:17:26 +0200 Subject: [PATCH 22/33] don't cache the MIR in the Stepper --- src/interpreter/stepper.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index f733d1d46c838..8807dbcafab6a 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -22,14 +22,12 @@ pub enum Event { pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, - 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 { - mir: fncx.mir(), fncx: fncx, process: Self::dummy, } @@ -38,7 +36,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn dummy(&mut self) -> EvalResult<()> { Ok(()) } fn statement(&mut self) -> EvalResult<()> { - let block_data = self.mir.basic_block_data(self.fncx.frame().next_block); + let mir = self.fncx.mir(); + let block_data = mir.basic_block_data(self.fncx.frame().next_block); let stmt = &block_data.statements[self.fncx.frame().stmt]; let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; let result = self.fncx.eval_assignment(lvalue, rvalue); @@ -51,7 +50,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx // after a terminator we go to a new block self.fncx.frame_mut().stmt = 0; let term = { - let block_data = self.mir.basic_block_data(self.fncx.frame().next_block); + let mir = self.fncx.mir(); + let block_data = mir.basic_block_data(self.fncx.frame().next_block); let terminator = block_data.terminator(); let result = self.fncx.eval_terminator(terminator); self.fncx.maybe_report(terminator.span, result)? @@ -61,13 +61,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx TerminatorTarget::Return => { assert!(self.fncx.frame().constants.is_empty()); self.fncx.pop_stack_frame(); - if !self.fncx.stack.is_empty() { - self.mir = self.fncx.mir(); - } - }, - TerminatorTarget::Call => { - self.mir = self.fncx.mir(); }, + TerminatorTarget::Call => {}, } Ok(()) } @@ -77,7 +72,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let def_id = cid.def_id(); let substs = cid.substs(); self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); - self.mir = self.fncx.mir(); Ok(()) } @@ -97,13 +91,13 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let block = self.fncx.frame().next_block; let stmt = self.fncx.frame().stmt; - let basic_block = self.mir.basic_block_data(block); + let mir = self.fncx.mir(); + let basic_block = mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { assert!(self.fncx.frame().constants.is_empty()); ConstantExtractor { span: stmt.span, - mir: &self.mir, gecx: self.fncx.gecx, frame: self.fncx.stack.last_mut().expect("stack empty"), }.visit_statement(block, stmt); @@ -120,7 +114,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx assert!(self.fncx.frame().constants.is_empty()); ConstantExtractor { span: terminator.span, - mir: &self.mir, gecx: self.fncx.gecx, frame: self.fncx.stack.last_mut().expect("stack empty"), }.visit_terminator(block, terminator); @@ -150,7 +143,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { span: Span, - mir: &'a CachedMir<'mir, 'tcx>, frame: &'a mut Frame<'mir, 'tcx>, gecx: &'a mut GlobalEvalContext<'b, 'tcx>, } @@ -194,7 +186,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> if self.gecx.statics.contains_key(&cid) { return; } - let mir = self.mir.promoted[index].clone(); + let mir = self.frame.mir.promoted[index].clone(); 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 mir = CachedMir::Owned(Rc::new(mir)); From 6b939bbd798c42b9e992da36f9158b711063a731 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 11:11:08 +0200 Subject: [PATCH 23/33] rebase leftovers --- src/interpreter/mod.rs | 88 ++++++++++++-------------------------- src/interpreter/stepper.rs | 7 +-- 2 files changed, 31 insertions(+), 64 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 22db69a2afff8..c1a91fee79761 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -194,6 +194,7 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { ty::FnDiverging => None, } } + // TODO(solson): Try making const_to_primval instead. fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult { use rustc::middle::const_val::ConstVal::*; @@ -337,6 +338,25 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { } } } + + fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + let substituted = ty.subst(self.tcx, substs); + self.tcx.normalize_associated_type(&substituted) + } + + fn type_size(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize { + self.type_layout(ty, substs).size(&self.tcx.data_layout).bytes() as usize + } + + fn type_layout(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout { + // TODO(solson): Is this inefficient? Needs investigation. + let ty = self.monomorphize(ty, substs); + + self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| { + // TODO(solson): Report this error properly. + ty.layout(&infcx).unwrap() + }) + } } impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { @@ -1308,49 +1328,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(Lvalue { ptr: ptr, extra: LvalueExtra::None }) } - // TODO(solson): Try making const_to_primval instead. - fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult { - use rustc::middle::const_val::ConstVal::*; - match *const_val { - Float(_f) => unimplemented!(), - Integral(int) => { - // TODO(solson): Check int constant type. - let ptr = self.memory.allocate(8); - self.memory.write_uint(ptr, int.to_u64_unchecked(), 8)?; - Ok(ptr) - } - Str(ref s) => { - let psize = self.memory.pointer_size; - let static_ptr = self.memory.allocate(s.len()); - let ptr = self.memory.allocate(psize * 2); - self.memory.write_bytes(static_ptr, s.as_bytes())?; - self.memory.write_ptr(ptr, static_ptr)?; - self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?; - Ok(ptr) - } - ByteStr(ref bs) => { - let psize = self.memory.pointer_size; - let static_ptr = self.memory.allocate(bs.len()); - let ptr = self.memory.allocate(psize); - self.memory.write_bytes(static_ptr, bs)?; - self.memory.write_ptr(ptr, static_ptr)?; - Ok(ptr) - } - Bool(b) => { - let ptr = self.memory.allocate(1); - self.memory.write_bool(ptr, b)?; - Ok(ptr) - } - Char(_c) => unimplemented!(), - Struct(_node_id) => unimplemented!(), - Tuple(_node_id) => unimplemented!(), - Function(_def_id) => unimplemented!(), - Array(_, _) => unimplemented!(), - Repeat(_, _) => unimplemented!(), - Dummy => unimplemented!(), - } - } - fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx)) } @@ -1360,12 +1337,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } fn monomorphize(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - let substituted = ty.subst(self.tcx, self.substs()); - self.tcx.normalize_associated_type(&substituted) - } - - fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment()) + self.gecx.monomorphize(ty, self.substs()) } fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> { @@ -1377,22 +1349,12 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(()) } - fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP) - } - fn type_size(&self, ty: Ty<'tcx>) -> usize { - self.type_layout(ty).size(&self.tcx.data_layout).bytes() as usize + self.gecx.type_size(ty, self.substs()) } fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout { - // TODO(solson): Is this inefficient? Needs investigation. - let ty = self.monomorphize(ty); - - self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| { - // TODO(solson): Report this error properly. - ty.layout(&infcx).unwrap() - }) + self.gecx.type_layout(ty, self.substs()) } pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult { @@ -1450,6 +1412,10 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn mir(&self) -> CachedMir<'mir, 'tcx> { self.frame().mir.clone() } + + fn substs(&self) -> &'tcx Substs<'tcx> { + self.frame().substs + } } fn pointee_type(ptr_ty: ty::Ty) -> Option { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 8807dbcafab6a..fffac08fc6f49 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -3,7 +3,8 @@ use super::{ CachedMir, TerminatorTarget, ConstantId, - GlobalEvalContext + GlobalEvalContext, + Frame, }; use error::EvalResult; use rustc::mir::repr as mir; @@ -41,7 +42,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let stmt = &block_data.statements[self.fncx.frame().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.fncx.maybe_report(result)?; self.fncx.frame_mut().stmt += 1; Ok(()) } @@ -54,7 +55,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx let block_data = mir.basic_block_data(self.fncx.frame().next_block); let terminator = block_data.terminator(); let result = self.fncx.eval_terminator(terminator); - self.fncx.maybe_report(terminator.span, result)? + self.fncx.maybe_report(result)? }; match term { TerminatorTarget::Block => {}, From 8b25bc8a9a709c516d986193bce7a74ed1861bcc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 11:11:33 +0200 Subject: [PATCH 24/33] directly push stackframes for constants when they are encountered --- src/interpreter/mod.rs | 8 ++--- src/interpreter/stepper.rs | 69 ++++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index c1a91fee79761..a05dfb734bf5b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -14,7 +14,7 @@ use std::rc::Rc; use std::{iter, mem}; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, DUMMY_SP, Span}; +use syntax::codemap::{self, DUMMY_SP}; use error::{EvalError, EvalResult}; use memory::{Memory, Pointer}; @@ -94,9 +94,6 @@ struct Frame<'a, 'tcx: 'a> { /// The index of the currently evaluated statment 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)] @@ -409,7 +406,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { loop { match stepper.step()? { - Constant => trace!("next statement requires the computation of a constant"), + Constant => trace!("computing a constant"), Assignment => trace!("{:?}", stepper.stmt()), Terminator => { trace!("{:?}", stepper.term().kind); @@ -444,7 +441,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { def_id: def_id, substs: substs, stmt: 0, - constants: Vec::new(), }); let locals: Vec = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index fffac08fc6f49..7499eb07ae918 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -4,7 +4,6 @@ use super::{ TerminatorTarget, ConstantId, GlobalEvalContext, - Frame, }; use error::EvalResult; use rustc::mir::repr as mir; @@ -13,6 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; use std::rc::Rc; +use memory::Pointer; pub enum Event { Constant, @@ -24,6 +24,10 @@ pub enum Event { pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{ fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>, 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> { @@ -31,6 +35,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Stepper { fncx: fncx, 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 { TerminatorTarget::Block => {}, TerminatorTarget::Return => { - assert!(self.fncx.frame().constants.is_empty()); self.fncx.pop_stack_frame(); }, TerminatorTarget::Call => {}, @@ -68,14 +72,6 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx 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 { (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); } - if !self.fncx.frame().constants.is_empty() { - self.process = Self::constant; - return Ok(Event::Constant); - } - let block = self.fncx.frame().next_block; let stmt = self.fncx.frame().stmt; let mir = self.fncx.mir(); let basic_block = mir.basic_block_data(block); if let Some(ref stmt) = basic_block.statements.get(stmt) { - assert!(self.fncx.frame().constants.is_empty()); + assert!(self.constants.is_empty()); ConstantExtractor { span: stmt.span, + substs: self.fncx.substs(), + def_id: self.fncx.frame().def_id, gecx: self.fncx.gecx, - frame: self.fncx.stack.last_mut().expect("stack empty"), + constants: &mut self.constants, + mir: &mir, }.visit_statement(block, stmt); - if self.fncx.frame().constants.is_empty() { + if self.constants.is_empty() { self.process = Self::statement; return Ok(Event::Assignment); } else { - self.process = Self::constant; + self.process = Self::statement; + self.extract_constants(); return Ok(Event::Constant); } } let terminator = basic_block.terminator(); - assert!(self.fncx.frame().constants.is_empty()); + assert!(self.constants.is_empty()); ConstantExtractor { span: terminator.span, + substs: self.fncx.substs(), + def_id: self.fncx.frame().def_id, gecx: self.fncx.gecx, - frame: self.fncx.stack.last_mut().expect("stack empty"), + constants: &mut self.constants, + mir: &mir, }.visit_terminator(block, terminator); - if self.fncx.frame().constants.is_empty() { + if self.constants.is_empty() { self.process = Self::terminator; Ok(Event::Terminator) } else { - self.process = Self::constant; + self.process = Self::statement; + self.extract_constants(); 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 pub fn stmt(&self) -> &mir::Statement { &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> { 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>, + mir: &'a mir::Mir<'tcx>, + def_id: DefId, + substs: &'tcx subst::Substs<'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 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.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 } => { let cid = ConstantId::Promoted { - def_id: self.frame.def_id, - substs: self.frame.substs, + def_id: self.def_id, + substs: self.substs, index: index, }; if self.gecx.statics.contains_key(&cid) { return; } - let mir = self.frame.mir.promoted[index].clone(); + let mir = self.mir.promoted[index].clone(); 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 mir = CachedMir::Owned(Rc::new(mir)); 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)); } } } From 3de30e33f50377d00c7222db1d98398e9a8bb41d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 11:34:56 +0200 Subject: [PATCH 25/33] no more function pointers --- src/interpreter/mod.rs | 24 ++++++-------- src/interpreter/stepper.rs | 66 ++++++++++++++------------------------ 2 files changed, 34 insertions(+), 56 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a05dfb734bf5b..896c740d8007a 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -400,22 +400,18 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn run(&mut self) -> EvalResult<()> { let mut stepper = stepper::Stepper::new(self); - 'outer: loop { + let mut done = false; + while !done { use self::stepper::Event::*; - trace!("// {:?}", stepper.block()); - - loop { - match stepper.step()? { - Constant => trace!("computing a constant"), - Assignment => trace!("{:?}", stepper.stmt()), - Terminator => { - trace!("{:?}", stepper.term().kind); - continue 'outer; - }, - Done => return Ok(()), - } - } + stepper.step(|event| match event { + Block(b) => trace!("// {:?}", b), + Assignment(a) => trace!("{:?}", a), + Terminator(t) => trace!("{:?}", t.kind), + Done => done = true, + _ => {}, + })?; } + Ok(()) } fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>, diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 7499eb07ae918..d6677c8c319be 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -14,16 +14,18 @@ use syntax::codemap::Span; use std::rc::Rc; use memory::Pointer; -pub enum Event { +pub enum Event<'a, 'tcx: 'a> { + Block(mir::BasicBlock), + Return, + Call, Constant, - Assignment, - Terminator, + 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>, - 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 @@ -34,17 +36,15 @@ 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 { fncx: fncx, - process: Self::dummy, constants: Vec::new(), } } - fn dummy(&mut self) -> EvalResult<()> { Ok(()) } - - fn statement(&mut self) -> EvalResult<()> { + fn statement FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { let mir = self.fncx.mir(); let block_data = mir.basic_block_data(self.fncx.frame().next_block); let stmt = &block_data.statements[self.fncx.frame().stmt]; + f(Event::Assignment(stmt)); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; let result = self.fncx.eval_assignment(lvalue, rvalue); self.fncx.maybe_report(result)?; @@ -52,33 +52,33 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Ok(()) } - fn terminator(&mut self) -> EvalResult<()> { + fn terminator FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { // after a terminator we go to a new block self.fncx.frame_mut().stmt = 0; let term = { let mir = self.fncx.mir(); let block_data = mir.basic_block_data(self.fncx.frame().next_block); let terminator = block_data.terminator(); + f(Event::Terminator(terminator)); let result = self.fncx.eval_terminator(terminator); self.fncx.maybe_report(result)? }; match term { - TerminatorTarget::Block => {}, + TerminatorTarget::Block => f(Event::Block(self.fncx.frame().next_block)), TerminatorTarget::Return => { + f(Event::Return); self.fncx.pop_stack_frame(); }, - TerminatorTarget::Call => {}, + TerminatorTarget::Call => f(Event::Call), } Ok(()) } - pub fn step(&mut self) -> EvalResult { - (self.process)(self)?; - + // returns true as long as there are more things to do + pub fn step FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { if self.fncx.stack.is_empty() { - // fuse the iterator - self.process = Self::dummy; - return Ok(Event::Done); + f(Event::Done); + return Ok(()); } let block = self.fncx.frame().next_block; @@ -97,12 +97,9 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_statement(block, stmt); if self.constants.is_empty() { - self.process = Self::statement; - return Ok(Event::Assignment); + return self.statement(f); } else { - self.process = Self::statement; - self.extract_constants(); - return Ok(Event::Constant); + return self.extract_constants(f); } } @@ -117,36 +114,21 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_terminator(block, terminator); if self.constants.is_empty() { - self.process = Self::terminator; - Ok(Event::Terminator) + self.terminator(f) } else { - self.process = Self::statement; - self.extract_constants(); - Ok(Event::Constant) + self.extract_constants(f) } } - fn extract_constants(&mut self) { + fn extract_constants FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { 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(); + f(Event::Constant); self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); } - } - - /// returns the statement that will be processed next - pub fn stmt(&self) -> &mir::Statement { - &self.fncx.basic_block().statements[self.fncx.frame().stmt] - } - - /// returns the terminator of the current block - pub fn term(&self) -> &mir::Terminator { - self.fncx.basic_block().terminator() - } - - pub fn block(&self) -> mir::BasicBlock { - self.fncx.frame().next_block + self.step(f) } } From 3868a62713245880145caca63a3e456c806a5bb9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 11:46:37 +0200 Subject: [PATCH 26/33] put `ConstantId`'s common fields into a struct --- src/interpreter/mod.rs | 44 +++++++++++++++++--------------------- src/interpreter/stepper.rs | 14 ++++++------ 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 896c740d8007a..a7e95af6bbf3f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -129,30 +129,18 @@ enum TerminatorTarget { } #[derive(Clone, Debug, Eq, PartialEq, Hash)] -enum ConstantId<'tcx> { - Promoted { def_id: DefId, substs: &'tcx Substs<'tcx>, index: usize }, - Static { def_id: DefId, substs: &'tcx Substs<'tcx> }, +struct ConstantId<'tcx> { + def_id: DefId, + substs: &'tcx Substs<'tcx>, + kind: ConstantKind, } -impl<'tcx> ConstantId<'tcx> { - fn substs(&self) -> &'tcx Substs<'tcx> { - use self::ConstantId::*; - match *self { - Promoted { substs, .. } | - Static { substs, .. } => substs - } - } - - fn def_id(&self) -> DefId { - use self::ConstantId::*; - match *self { - Promoted { def_id, .. } | - Static { def_id, .. } => def_id, - } - } +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +enum ConstantKind { + Promoted(usize), + Static, } - impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self { GlobalEvalContext { @@ -1208,15 +1196,19 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { if item_ty.ty.is_fn() { Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string())) } else { - let cid = ConstantId::Static{ def_id: def_id, substs: substs }; + let cid = ConstantId { + def_id: def_id, + substs: substs, + kind: ConstantKind::Static, + }; Ok(*self.statics.get(&cid).expect("static should have been cached (rvalue)")) } }, Promoted { index } => { - let cid = ConstantId::Promoted { + let cid = ConstantId { def_id: self.frame().def_id, substs: self.substs(), - index: index, + kind: ConstantKind::Promoted(index), }; Ok(*self.statics.get(&cid).expect("a promoted constant hasn't been precomputed")) }, @@ -1236,7 +1228,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Static(def_id) => { let substs = self.tcx.mk_substs(subst::Substs::empty()); - let cid = ConstantId::Static{ def_id: def_id, substs: substs }; + let cid = ConstantId { + def_id: def_id, + substs: substs, + kind: ConstantKind::Static, + }; *self.gecx.statics.get(&cid).expect("static should have been cached (lvalue)") }, diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index d6677c8c319be..c0e9249b29250 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -4,6 +4,7 @@ use super::{ TerminatorTarget, ConstantId, GlobalEvalContext, + ConstantKind, }; use error::EvalResult; use rustc::mir::repr as mir; @@ -123,10 +124,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx fn extract_constants FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { 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(); f(Event::Constant); - self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr)); + self.fncx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr)); } self.step(f) } @@ -143,9 +142,10 @@ struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { - let cid = ConstantId::Static { + let cid = ConstantId { def_id: def_id, substs: substs, + kind: ConstantKind::Static, }; if self.gecx.statics.contains_key(&cid) { return; @@ -172,17 +172,17 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> } }, mir::Literal::Promoted { index } => { - let cid = ConstantId::Promoted { + let cid = ConstantId { def_id: self.def_id, substs: self.substs, - index: index, + kind: ConstantKind::Promoted(index), }; if self.gecx.statics.contains_key(&cid) { return; } let mir = self.mir.promoted[index].clone(); 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)); self.gecx.statics.insert(cid.clone(), return_ptr); self.constants.push((cid, constant.span, return_ptr, mir)); From 240f0c0dd64f0091f98d1c6dd543d306d60ee29c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 12:30:25 +0200 Subject: [PATCH 27/33] improve fn argument naming --- src/interpreter/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a7e95af6bbf3f..774db299db6f4 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -170,8 +170,8 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { Ok(return_ptr) } - fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { - match ty { + fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option { + match output_ty { ty::FnConverging(ty) => { let size = self.type_size(ty, substs); Some(self.memory.allocate(size)) From 2178961262e464151bb33feeaaae04fb272d4856 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 12:35:15 +0200 Subject: [PATCH 28/33] improve the docs of ConstantId --- src/interpreter/mod.rs | 13 ++++++++++--- src/interpreter/stepper.rs | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 774db299db6f4..1942727e47694 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -129,8 +129,14 @@ enum TerminatorTarget { } #[derive(Clone, Debug, Eq, PartialEq, Hash)] +/// Uniquely identifies a specific constant or static struct ConstantId<'tcx> { + /// the def id of the constant/static or in case of promoteds, the def id of the function they belong to def_id: DefId, + /// In case of statics and constants this is `Substs::empty()`, so only promoteds and associated + /// constants actually have something useful here. We could special case statics and constants, + /// but that would only require more branching when working with constants, and not bring any + /// real benefits. substs: &'tcx Substs<'tcx>, kind: ConstantKind, } @@ -138,7 +144,8 @@ struct ConstantId<'tcx> { #[derive(Clone, Debug, Eq, PartialEq, Hash)] enum ConstantKind { Promoted(usize), - Static, + /// Statics, constants and associated constants + Global, } impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { @@ -1199,7 +1206,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let cid = ConstantId { def_id: def_id, substs: substs, - kind: ConstantKind::Static, + kind: ConstantKind::Global, }; Ok(*self.statics.get(&cid).expect("static should have been cached (rvalue)")) } @@ -1231,7 +1238,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let cid = ConstantId { def_id: def_id, substs: substs, - kind: ConstantKind::Static, + kind: ConstantKind::Global, }; *self.gecx.statics.get(&cid).expect("static should have been cached (lvalue)") }, diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index c0e9249b29250..f9bf5c2d3b853 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -145,7 +145,7 @@ impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { let cid = ConstantId { def_id: def_id, substs: substs, - kind: ConstantKind::Static, + kind: ConstantKind::Global, }; if self.gecx.statics.contains_key(&cid) { return; From cbbf58bbaaafb9cdd9cb837bc3570a8b04bc734a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Jun 2016 12:47:24 +0200 Subject: [PATCH 29/33] the statement/terminator has already been computed, don't do it again --- src/interpreter/stepper.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index f9bf5c2d3b853..60eae047f1bf1 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -41,10 +41,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } } - fn statement FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { - let mir = self.fncx.mir(); - let block_data = mir.basic_block_data(self.fncx.frame().next_block); - let stmt = &block_data.statements[self.fncx.frame().stmt]; + fn statement FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { f(Event::Assignment(stmt)); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; let result = self.fncx.eval_assignment(lvalue, rvalue); @@ -53,13 +50,10 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Ok(()) } - fn terminator FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { + fn terminator FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { // after a terminator we go to a new block self.fncx.frame_mut().stmt = 0; let term = { - let mir = self.fncx.mir(); - let block_data = mir.basic_block_data(self.fncx.frame().next_block); - let terminator = block_data.terminator(); f(Event::Terminator(terminator)); let result = self.fncx.eval_terminator(terminator); self.fncx.maybe_report(result)? @@ -98,7 +92,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_statement(block, stmt); if self.constants.is_empty() { - return self.statement(f); + return self.statement(f, stmt); } else { return self.extract_constants(f); } @@ -115,7 +109,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_terminator(block, terminator); if self.constants.is_empty() { - self.terminator(f) + self.terminator(f, terminator) } else { self.extract_constants(f) } @@ -133,6 +127,7 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { span: Span, + // FIXME: directly push the new stackframes instead of doing this intermediate caching constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>, gecx: &'a mut GlobalEvalContext<'b, 'tcx>, mir: &'a mir::Mir<'tcx>, From 59d858a0b142a718a771bdcc3c1f096e3ae01d5f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 10:52:45 +0200 Subject: [PATCH 30/33] refactor away the closures and `Event` enum --- src/interpreter/mod.rs | 12 +--------- src/interpreter/stepper.rs | 46 ++++++++++++++++---------------------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 1942727e47694..b581e860d7848 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -395,17 +395,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { fn run(&mut self) -> EvalResult<()> { let mut stepper = stepper::Stepper::new(self); - let mut done = false; - while !done { - use self::stepper::Event::*; - stepper.step(|event| match event { - Block(b) => trace!("// {:?}", b), - Assignment(a) => trace!("{:?}", a), - Terminator(t) => trace!("{:?}", t.kind), - Done => done = true, - _ => {}, - })?; - } + while stepper.step()? {} Ok(()) } diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 60eae047f1bf1..50aaba1d73f13 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -15,16 +15,6 @@ use syntax::codemap::Span; use std::rc::Rc; use memory::Pointer; -pub enum Event<'a, 'tcx: 'a> { - Block(mir::BasicBlock), - Return, - Call, - Constant, - 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>, @@ -41,8 +31,8 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx } } - fn statement FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { - f(Event::Assignment(stmt)); + fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { + trace!("{:?}", stmt); let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind; let result = self.fncx.eval_assignment(lvalue, rvalue); self.fncx.maybe_report(result)?; @@ -50,30 +40,28 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx Ok(()) } - fn terminator FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { + fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { // after a terminator we go to a new block self.fncx.frame_mut().stmt = 0; let term = { - f(Event::Terminator(terminator)); + trace!("{:?}", terminator.kind); let result = self.fncx.eval_terminator(terminator); self.fncx.maybe_report(result)? }; match term { - TerminatorTarget::Block => f(Event::Block(self.fncx.frame().next_block)), TerminatorTarget::Return => { - f(Event::Return); self.fncx.pop_stack_frame(); }, - TerminatorTarget::Call => f(Event::Call), + TerminatorTarget::Block | + TerminatorTarget::Call => trace!("// {:?}", self.fncx.frame().next_block), } Ok(()) } // returns true as long as there are more things to do - pub fn step FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { + pub fn step(&mut self) -> EvalResult { if self.fncx.stack.is_empty() { - f(Event::Done); - return Ok(()); + return Ok(false); } let block = self.fncx.frame().next_block; @@ -92,10 +80,11 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_statement(block, stmt); if self.constants.is_empty() { - return self.statement(f, stmt); + self.statement(stmt)?; } else { - return self.extract_constants(f); + self.extract_constants()?; } + return Ok(true); } let terminator = basic_block.terminator(); @@ -109,19 +98,22 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx mir: &mir, }.visit_terminator(block, terminator); if self.constants.is_empty() { - self.terminator(f, terminator) + self.terminator(terminator)?; } else { - self.extract_constants(f) + self.extract_constants()?; } + Ok(true) } - fn extract_constants FnMut(Event<'f, 'tcx>)>(&mut self, mut f: F) -> EvalResult<()> { + fn extract_constants(&mut self) -> EvalResult<()> { assert!(!self.constants.is_empty()); for (cid, span, return_ptr, mir) in self.constants.drain(..) { - f(Event::Constant); + trace!("queuing a constant"); self.fncx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr)); } - self.step(f) + // self.step() can't be "done", so it can't return false + assert!(self.step()?); + Ok(()) } } From 225a6a272d6fa9c945e9e55f2070f736844c2781 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 11:16:09 +0200 Subject: [PATCH 31/33] we already have the constant's type, no need to recompute from the def_id --- src/interpreter/mod.rs | 5 ++--- src/interpreter/stepper.rs | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index b581e860d7848..15fa4cdd3b842 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1184,13 +1184,12 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { use rustc::mir::repr::Operand::*; match *op { Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()), - Constant(mir::Constant { ref literal, .. }) => { + Constant(mir::Constant { ref literal, ty, .. }) => { use rustc::mir::repr::Literal::*; match *literal { Value { ref value } => Ok(self.const_to_ptr(value)?), Item { def_id, substs } => { - let item_ty = self.tcx.lookup_item_type(def_id).subst(self.tcx, substs); - if item_ty.ty.is_fn() { + if ty.is_fn() { Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string())) } else { let cid = ConstantId { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 50aaba1d73f13..587239fdf068d 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -8,7 +8,7 @@ use super::{ }; use error::EvalResult; use rustc::mir::repr as mir; -use rustc::ty::subst::{self, Subst}; +use rustc::ty::subst; use rustc::hir::def_id::DefId; use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; @@ -151,9 +151,10 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> // already computed by rustc mir::Literal::Value { .. } => {} mir::Literal::Item { def_id, substs } => { - let item_ty = self.gecx.tcx.lookup_item_type(def_id).subst(self.gecx.tcx, substs); - if item_ty.ty.is_fn() { - // unimplemented + if constant.ty.is_fn() { + // No need to do anything here, even if function pointers are implemented, + // because the type is the actual function, not the signature of the function. + // Thus we can simply create a zero sized allocation in `evaluate_operand` } else { self.static_item(def_id, substs, constant.span); } From 040a501a68d85179d0fb8c5bf409f8e93ba12aeb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 11:27:02 +0200 Subject: [PATCH 32/33] make sure globals that yield function pointers aren't treated like functions --- src/interpreter/mod.rs | 2 +- src/interpreter/stepper.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 15fa4cdd3b842..6c0d58f1c47e7 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1189,7 +1189,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { match *literal { Value { ref value } => Ok(self.const_to_ptr(value)?), Item { def_id, substs } => { - if ty.is_fn() { + if let ty::TyFnDef(..) = ty.sty { Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string())) } else { let cid = ConstantId { diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 587239fdf068d..db7b129eee601 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -8,7 +8,7 @@ use super::{ }; use error::EvalResult; use rustc::mir::repr as mir; -use rustc::ty::subst; +use rustc::ty::{subst, self}; use rustc::hir::def_id::DefId; use rustc::mir::visit::{Visitor, LvalueContext}; use syntax::codemap::Span; @@ -151,7 +151,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> // already computed by rustc mir::Literal::Value { .. } => {} mir::Literal::Item { def_id, substs } => { - if constant.ty.is_fn() { + if let ty::TyFnDef(..) = constant.ty.sty { // No need to do anything here, even if function pointers are implemented, // because the type is the actual function, not the signature of the function. // Thus we can simply create a zero sized allocation in `evaluate_operand` From 05eaa522a5486ba20bb564bf2b37179124d0951c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Jun 2016 11:27:12 +0200 Subject: [PATCH 33/33] rename `static_item` to `global_item` --- src/interpreter/stepper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index db7b129eee601..a113b8f98e813 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -128,7 +128,7 @@ struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> { } impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> { - fn static_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { + fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) { let cid = ConstantId { def_id: def_id, substs: substs, @@ -156,7 +156,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> // because the type is the actual function, not the signature of the function. // Thus we can simply create a zero sized allocation in `evaluate_operand` } else { - self.static_item(def_id, substs, constant.span); + self.global_item(def_id, substs, constant.span); } }, mir::Literal::Promoted { index } => { @@ -183,7 +183,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> if let mir::Lvalue::Static(def_id) = *lvalue { let substs = self.gecx.tcx.mk_substs(subst::Substs::empty()); let span = self.span; - self.static_item(def_id, substs, span); + self.global_item(def_id, substs, span); } } }