Skip to content

Commit 924f24a

Browse files
authored
Rollup merge of rust-lang#49274 - oli-obk:slow_miri, r=michaelwoerister,eddyb
Remove slow HashSet during miri stack frame creation fixes rust-lang#49237 probably has a major impact on rust-lang#48846 r? @michaelwoerister cc @eddyb I know you kept telling me to use vectors instead of hash containers... Now I know why.
2 parents 2b2f916 + f9019ae commit 924f24a

File tree

3 files changed

+44
-58
lines changed

3 files changed

+44
-58
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
use std::collections::HashSet;
21
use std::fmt::Write;
32

43
use rustc::hir::def_id::DefId;
4+
use rustc::hir::def::Def;
55
use rustc::hir::map::definitions::DefPathData;
66
use rustc::middle::const_val::{ConstVal, ErrKind};
77
use rustc::mir;
88
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
99
use rustc::ty::subst::{Subst, Substs};
1010
use rustc::ty::{self, Ty, TyCtxt};
1111
use rustc::ty::maps::TyCtxtAt;
12-
use rustc_data_structures::indexed_vec::Idx;
12+
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
1313
use rustc::middle::const_val::FrameInfo;
1414
use syntax::codemap::{self, Span};
1515
use syntax::ast::Mutability;
1616
use rustc::mir::interpret::{
1717
GlobalId, Value, Pointer, PrimVal, PrimValKind,
1818
EvalError, EvalResult, EvalErrorKind, MemoryPointer,
1919
};
20+
use std::mem;
2021

2122
use super::{Place, PlaceExtra, Memory,
2223
HasMemory, MemoryKind,
@@ -71,12 +72,12 @@ pub struct Frame<'mir, 'tcx: 'mir> {
7172
pub return_place: Place,
7273

7374
/// The list of locals for this stack frame, stored in order as
74-
/// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
75+
/// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
7576
/// `None` represents a local that is currently dead, while a live local
7677
/// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
7778
///
7879
/// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`.
79-
pub locals: Vec<Option<Value>>,
80+
pub locals: IndexVec<mir::Local, Option<Value>>,
8081

8182
////////////////////////////////////////////////////////////////////////////////
8283
// Current position within the function
@@ -383,39 +384,29 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
383384
) -> EvalResult<'tcx> {
384385
::log_settings::settings().indentation += 1;
385386

386-
/// Return the set of locals that have a storage annotation anywhere
387-
fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet<mir::Local> {
388-
use rustc::mir::StatementKind::*;
389-
390-
let mut set = HashSet::new();
391-
for block in mir.basic_blocks() {
392-
for stmt in block.statements.iter() {
393-
match stmt.kind {
394-
StorageLive(local) |
395-
StorageDead(local) => {
396-
set.insert(local);
387+
let locals = if mir.local_decls.len() > 1 {
388+
let mut locals = IndexVec::from_elem(Some(Value::ByVal(PrimVal::Undef)), &mir.local_decls);
389+
match self.tcx.describe_def(instance.def_id()) {
390+
// statics and constants don't have `Storage*` statements, no need to look for them
391+
Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
392+
_ => {
393+
trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len());
394+
for block in mir.basic_blocks() {
395+
for stmt in block.statements.iter() {
396+
use rustc::mir::StatementKind::{StorageDead, StorageLive};
397+
match stmt.kind {
398+
StorageLive(local) |
399+
StorageDead(local) => locals[local] = None,
400+
_ => {}
401+
}
397402
}
398-
_ => {}
399403
}
400-
}
401-
}
402-
set
403-
}
404-
405-
// Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local
406-
// `Value` for that.
407-
let num_locals = mir.local_decls.len() - 1;
408-
409-
let locals = {
410-
let annotated_locals = collect_storage_annotations(mir);
411-
let mut locals = vec![None; num_locals];
412-
for i in 0..num_locals {
413-
let local = mir::Local::new(i + 1);
414-
if !annotated_locals.contains(&local) {
415-
locals[i] = Some(Value::ByVal(PrimVal::Undef));
416-
}
404+
},
417405
}
418406
locals
407+
} else {
408+
// don't allocate at all for trivial constants
409+
IndexVec::new()
419410
};
420411

421412
self.stack.push(Frame {
@@ -973,8 +964,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
973964
pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
974965
let new_place = match place {
975966
Place::Local { frame, local } => {
976-
// -1 since we don't store the return value
977-
match self.stack[frame].locals[local.index() - 1] {
967+
match self.stack[frame].locals[local] {
978968
None => return err!(DeadLocal),
979969
Some(Value::ByRef(ptr, align)) => {
980970
Place::Ptr {
@@ -988,7 +978,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
988978
let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
989979
let layout = self.layout_of(ty)?;
990980
let ptr = self.alloc_ptr(ty)?;
991-
self.stack[frame].locals[local.index() - 1] =
981+
self.stack[frame].locals[local] =
992982
Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
993983
let place = Place::from_ptr(ptr, layout.align);
994984
self.write_value(ValTy { value: val, ty }, place)?;
@@ -1702,13 +1692,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
17021692

17031693
impl<'mir, 'tcx> Frame<'mir, 'tcx> {
17041694
pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
1705-
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1706-
self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
1695+
self.locals[local].ok_or(EvalErrorKind::DeadLocal.into())
17071696
}
17081697

17091698
fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1710-
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1711-
match self.locals[local.index() - 1] {
1699+
match self.locals[local] {
17121700
None => err!(DeadLocal),
17131701
Some(ref mut local) => {
17141702
*local = value;
@@ -1717,20 +1705,17 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> {
17171705
}
17181706
}
17191707

1720-
pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1708+
pub fn storage_live(&mut self, local: mir::Local) -> Option<Value> {
17211709
trace!("{:?} is now live", local);
17221710

1723-
let old = self.locals[local.index() - 1];
1724-
self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored
1725-
return Ok(old);
1711+
// StorageLive *always* kills the value that's currently stored
1712+
mem::replace(&mut self.locals[local], Some(Value::ByVal(PrimVal::Undef)))
17261713
}
17271714

17281715
/// Returns the old value of the local
1729-
pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1716+
pub fn storage_dead(&mut self, local: mir::Local) -> Option<Value> {
17301717
trace!("{:?} is now dead", local);
17311718

1732-
let old = self.locals[local.index() - 1];
1733-
self.locals[local.index() - 1] = None;
1734-
return Ok(old);
1719+
self.locals[local].take()
17351720
}
17361721
}

src/librustc_mir/interpret/memory.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
2-
use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
2+
use std::collections::{btree_map, BTreeMap, VecDeque};
33
use std::{ptr, io};
44

55
use rustc::ty::Instance;
66
use rustc::ty::maps::TyCtxtAt;
77
use rustc::ty::layout::{self, Align, TargetDataLayout};
88
use syntax::ast::Mutability;
99

10+
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
1011
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
1112
EvalResult, PrimVal, EvalErrorKind};
1213

@@ -33,15 +34,15 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
3334
pub data: M::MemoryData,
3435

3536
/// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
36-
alloc_kind: HashMap<AllocId, MemoryKind<M::MemoryKinds>>,
37+
alloc_kind: FxHashMap<AllocId, MemoryKind<M::MemoryKinds>>,
3738

3839
/// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations).
39-
alloc_map: HashMap<AllocId, Allocation>,
40+
alloc_map: FxHashMap<AllocId, Allocation>,
4041

4142
/// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations).
4243
///
4344
/// Stores statics while they are being processed, before they are interned and thus frozen
44-
uninitialized_statics: HashMap<AllocId, Allocation>,
45+
uninitialized_statics: FxHashMap<AllocId, Allocation>,
4546

4647
/// The current stack frame. Used to check accesses against locks.
4748
pub cur_frame: usize,
@@ -53,9 +54,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
5354
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
5455
Memory {
5556
data,
56-
alloc_kind: HashMap::new(),
57-
alloc_map: HashMap::new(),
58-
uninitialized_statics: HashMap::new(),
57+
alloc_kind: FxHashMap::default(),
58+
alloc_map: FxHashMap::default(),
59+
uninitialized_statics: FxHashMap::default(),
5960
tcx,
6061
cur_frame: usize::max_value(),
6162
}
@@ -338,7 +339,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
338339
allocs.sort();
339340
allocs.dedup();
340341
let mut allocs_to_print = VecDeque::from(allocs);
341-
let mut allocs_seen = HashSet::new();
342+
let mut allocs_seen = FxHashSet::default();
342343

343344
while let Some(id) = allocs_to_print.pop_front() {
344345
let mut msg = format!("Alloc {:<5} ", format!("{}:", id));

src/librustc_mir/interpret/step.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
6969

7070
// Mark locals as alive
7171
StorageLive(local) => {
72-
let old_val = self.frame_mut().storage_live(local)?;
72+
let old_val = self.frame_mut().storage_live(local);
7373
self.deallocate_local(old_val)?;
7474
}
7575

7676
// Mark locals as dead
7777
StorageDead(local) => {
78-
let old_val = self.frame_mut().storage_dead(local)?;
78+
let old_val = self.frame_mut().storage_dead(local);
7979
self.deallocate_local(old_val)?;
8080
}
8181

0 commit comments

Comments
 (0)