diff options
author | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2018-01-16 09:31:48 +0100 |
---|---|---|
committer | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2018-03-08 08:34:05 +0100 |
commit | b33e4e784e9906c732dcb3e0b6872f65dc8f5597 (patch) | |
tree | 13e1196b1fb3c26f969d5f6e7e28003bf76e058e /src/librustc_mir/interpret/step.rs | |
parent | Prepare for using miri in trans (diff) | |
download | grust-b33e4e784e9906c732dcb3e0b6872f65dc8f5597.tar.gz grust-b33e4e784e9906c732dcb3e0b6872f65dc8f5597.tar.bz2 grust-b33e4e784e9906c732dcb3e0b6872f65dc8f5597.tar.xz |
Fully use miri in trans
Diffstat (limited to 'src/librustc_mir/interpret/step.rs')
-rw-r--r-- | src/librustc_mir/interpret/step.rs | 241 |
1 files changed, 7 insertions, 234 deletions
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 2b0f9041d5..21e81ff668 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs | |||
@@ -2,21 +2,12 @@ | |||
2 | //! | 2 | //! |
3 | //! The main entry point is the `step` method. | 3 | //! The main entry point is the `step` method. |
4 | 4 | ||
5 | use rustc::hir; | ||
6 | use rustc::mir::visit::{Visitor, PlaceContext}; | ||
7 | use rustc::mir; | 5 | use rustc::mir; |
8 | use rustc::ty::{self, Instance}; | ||
9 | use rustc::ty::layout::LayoutOf; | ||
10 | use rustc::middle::const_val::ConstVal; | ||
11 | use rustc::mir::interpret::GlobalId; | ||
12 | 6 | ||
13 | use rustc::mir::interpret::{EvalResult, EvalErrorKind}; | 7 | use rustc::mir::interpret::EvalResult; |
14 | use super::{EvalContext, StackPopCleanup, Place, Machine}; | 8 | use super::{EvalContext, Machine}; |
15 | 9 | ||
16 | use syntax::codemap::Span; | 10 | impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { |
17 | use syntax::ast::Mutability; | ||
18 | |||
19 | impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { | ||
20 | pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { | 11 | pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { |
21 | self.steps_remaining = self.steps_remaining.saturating_sub(n); | 12 | self.steps_remaining = self.steps_remaining.saturating_sub(n); |
22 | if self.steps_remaining > 0 { | 13 | if self.steps_remaining > 0 { |
@@ -41,52 +32,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { | |||
41 | let old_frames = self.cur_frame(); | 32 | let old_frames = self.cur_frame(); |
42 | 33 | ||
43 | if let Some(stmt) = basic_block.statements.get(stmt_id) { | 34 | if let Some(stmt) = basic_block.statements.get(stmt_id) { |
44 | let mut new = Ok(false); | 35 | assert_eq!(old_frames, self.cur_frame()); |
45 | ConstantExtractor { | 36 | self.statement(stmt)?; |
46 | span: stmt.source_info.span, | ||
47 | instance: self.frame().instance, | ||
48 | ecx: self, | ||
49 | mir, | ||
50 | new_constant: &mut new, | ||
51 | }.visit_statement( | ||
52 | block, | ||
53 | stmt, | ||
54 | mir::Location { | ||
55 | block, | ||
56 | statement_index: stmt_id, | ||
57 | }, | ||
58 | ); | ||
59 | // if ConstantExtractor added a new frame, we don't execute anything here | ||
60 | // but await the next call to step | ||
61 | if !new? { | ||
62 | assert_eq!(old_frames, self.cur_frame()); | ||
63 | self.statement(stmt)?; | ||
64 | } | ||
65 | return Ok(true); | 37 | return Ok(true); |
66 | } | 38 | } |
67 | 39 | ||
68 | let terminator = basic_block.terminator(); | 40 | let terminator = basic_block.terminator(); |
69 | let mut new = Ok(false); | 41 | assert_eq!(old_frames, self.cur_frame()); |
70 | ConstantExtractor { | 42 | self.terminator(terminator)?; |
71 | span: terminator.source_info.span, | ||
72 | instance: self.frame().instance, | ||
73 | ecx: self, | ||
74 | mir, | ||
75 | new_constant: &mut new, | ||
76 | }.visit_terminator( | ||
77 | block, | ||
78 | terminator, | ||
79 | mir::Location { | ||
80 | block, | ||
81 | statement_index: stmt_id, | ||
82 | }, | ||
83 | ); | ||
84 | // if ConstantExtractor added a new frame, we don't execute anything here | ||
85 | // but await the next call to step | ||
86 | if !new? { | ||
87 | assert_eq!(old_frames, self.cur_frame()); | ||
88 | self.terminator(terminator)?; | ||
89 | } | ||
90 | Ok(true) | 43 | Ok(true) |
91 | } | 44 | } |
92 | 45 | ||
@@ -152,184 +105,4 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { | |||
152 | } | 105 | } |
153 | Ok(()) | 106 | Ok(()) |
154 | } | 107 | } |
155 | |||
156 | /// returns `true` if a stackframe was pushed | ||
157 | fn global_item( | ||
158 | &mut self, | ||
159 | instance: Instance<'tcx>, | ||
160 | span: Span, | ||
161 | mutability: Mutability, | ||
162 | ) -> EvalResult<'tcx, bool> { | ||
163 | debug!("global_item: {:?}", instance); | ||
164 | let cid = GlobalId { | ||
165 | instance, | ||
166 | promoted: None, | ||
167 | }; | ||
168 | if self.tcx.interpret_interner.borrow().get_cached(cid).is_some() { | ||
169 | return Ok(false); | ||
170 | } | ||
171 | if self.tcx.has_attr(instance.def_id(), "linkage") { | ||
172 | M::global_item_with_linkage(self, cid.instance, mutability)?; | ||
173 | return Ok(false); | ||
174 | } | ||
175 | let instance_ty = instance.ty(self.tcx); | ||
176 | let layout = self.layout_of(instance_ty)?; | ||
177 | assert!(!layout.is_unsized()); | ||
178 | let ptr = self.memory.allocate( | ||
179 | layout.size.bytes(), | ||
180 | layout.align, | ||
181 | None, | ||
182 | )?; | ||
183 | self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); | ||
184 | let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span); | ||
185 | let mutability = if mutability == Mutability::Mutable || internally_mutable { | ||
186 | Mutability::Mutable | ||
187 | } else { | ||
188 | Mutability::Immutable | ||
189 | }; | ||
190 | let cleanup = StackPopCleanup::MarkStatic(mutability); | ||
191 | let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); | ||
192 | trace!("pushing stack frame for global: {}", name); | ||
193 | let mir = self.load_mir(instance.def)?; | ||
194 | self.push_stack_frame( | ||
195 | instance, | ||
196 | span, | ||
197 | mir, | ||
198 | Place::from_ptr(ptr, layout.align), | ||
199 | cleanup, | ||
200 | )?; | ||
201 | Ok(true) | ||
202 | } | ||
203 | } | ||
204 | |||
205 | struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> { | ||
206 | span: Span, | ||
207 | ecx: &'a mut EvalContext<'b, 'tcx, M>, | ||
208 | mir: &'tcx mir::Mir<'tcx>, | ||
209 | instance: ty::Instance<'tcx>, | ||
210 | // Whether a stackframe for a new constant has been pushed | ||
211 | new_constant: &'a mut EvalResult<'tcx, bool>, | ||
212 | } | ||
213 | |||
214 | impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> { | ||
215 | fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, bool>>(&mut self, f: F) { | ||
216 | match *self.new_constant { | ||
217 | // already computed a constant, don't do more than one per iteration | ||
218 | Ok(true) => {}, | ||
219 | // no constants computed yet | ||
220 | Ok(false) => *self.new_constant = f(self), | ||
221 | // error happened, abort the visitor traversing | ||
222 | Err(_) => {}, | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> { | ||
228 | fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) { | ||
229 | self.super_constant(constant, location); | ||
230 | self.try(|this| { | ||
231 | match constant.literal { | ||
232 | // already computed by rustc | ||
233 | mir::Literal::Value { value: &ty::Const { val: ConstVal::Unevaluated(def_id, substs), .. } } => { | ||
234 | debug!("global_item: {:?}, {:#?}", def_id, substs); | ||
235 | let substs = this.ecx.tcx.trans_apply_param_substs(this.instance.substs, &substs); | ||
236 | debug!("global_item_new_substs: {:#?}", substs); | ||
237 | debug!("global_item_param_env: {:#?}", this.ecx.param_env); | ||
238 | let instance = Instance::resolve( | ||
239 | this.ecx.tcx, | ||
240 | this.ecx.param_env, | ||
241 | def_id, | ||
242 | substs, | ||
243 | ).ok_or(EvalErrorKind::TypeckError)?; // turn error prop into a panic to expose associated type in const issue | ||
244 | this.ecx.global_item( | ||
245 | instance, | ||
246 | constant.span, | ||
247 | Mutability::Immutable, | ||
248 | ) | ||
249 | } | ||
250 | mir::Literal::Value { .. } => Ok(false), | ||
251 | mir::Literal::Promoted { index } => { | ||
252 | let cid = GlobalId { | ||
253 | instance: this.instance, | ||
254 | promoted: Some(index), | ||
255 | }; | ||
256 | if this.ecx.tcx.interpret_interner.borrow().get_cached(cid).is_some() { | ||
257 | return Ok(false); | ||
258 | } | ||
259 | let mir = &this.mir.promoted[index]; | ||
260 | let ty = this.ecx.monomorphize(mir.return_ty(), this.instance.substs); | ||
261 | let layout = this.ecx.layout_of(ty)?; | ||
262 | assert!(!layout.is_unsized()); | ||
263 | let ptr = this.ecx.memory.allocate( | ||
264 | layout.size.bytes(), | ||
265 | layout.align, | ||
266 | None, | ||
267 | )?; | ||
268 | this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); | ||
269 | trace!("pushing stack frame for {:?}", index); | ||
270 | this.ecx.push_stack_frame( | ||
271 | this.instance, | ||
272 | constant.span, | ||
273 | mir, | ||
274 | Place::from_ptr(ptr, layout.align), | ||
275 | StackPopCleanup::MarkStatic(Mutability::Immutable), | ||
276 | )?; | ||
277 | Ok(true) | ||
278 | } | ||
279 | } | ||
280 | }); | ||
281 | } | ||
282 | |||
283 | fn visit_place( | ||
284 | &mut self, | ||
285 | place: &mir::Place<'tcx>, | ||
286 | context: PlaceContext<'tcx>, | ||
287 | location: mir::Location, | ||
288 | ) { | ||
289 | self.super_place(place, context, location); | ||
290 | self.try(|this| { | ||
291 | if let mir::Place::Static(ref static_) = *place { | ||
292 | let def_id = static_.def_id; | ||
293 | let span = this.span; | ||
294 | if let Some(node_item) = this.ecx.tcx.hir.get_if_local(def_id) { | ||
295 | if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item { | ||
296 | if let hir::ItemStatic(_, m, _) = *node { | ||
297 | let instance = Instance::mono(this.ecx.tcx, def_id); | ||
298 | this.ecx.global_item( | ||
299 | instance, | ||
300 | span, | ||
301 | if m == hir::MutMutable { | ||
302 | Mutability::Mutable | ||
303 | } else { | ||
304 | Mutability::Immutable | ||
305 | }, | ||
306 | ) | ||
307 | } else { | ||
308 | bug!("static def id doesn't point to static"); | ||
309 | } | ||
310 | } else { | ||
311 | bug!("static def id doesn't point to item"); | ||
312 | } | ||
313 | } else { | ||
314 | let def = this.ecx.tcx.describe_def(def_id).expect("static not found"); | ||
315 | if let hir::def::Def::Static(_, mutable) = def { | ||
316 | let instance = Instance::mono(this.ecx.tcx, def_id); | ||
317 | this.ecx.global_item( | ||
318 | instance, | ||
319 | span, | ||
320 | if mutable { | ||
321 | Mutability::Mutable | ||
322 | } else { | ||
323 | Mutability::Immutable | ||
324 | }, | ||
325 | ) | ||
326 | } else { | ||
327 | bug!("static found but isn't a static: {:?}", def); | ||
328 | } | ||
329 | } | ||
330 | } else { | ||
331 | Ok(false) | ||
332 | } | ||
333 | }); | ||
334 | } | ||
335 | } | 108 | } |