diff options
| author | bors <bors@rust-lang.org> | 2020-09-22 22:52:07 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-09-22 22:52:07 +0000 |
| commit | 6d3acf5129767db78a3d9d62e814ec86b8870d75 (patch) | |
| tree | ad854851aeb92cfe2475a3b7b1dfda6ce1c4dc1b /compiler/rustc_data_structures | |
| parent | 0da58007451a154da2480160429e1604a1f5f0ec (diff) | |
| parent | 1146c39da74b3875e6667aeeafde2773644dc8b6 (diff) | |
| download | rust-6d3acf5129767db78a3d9d62e814ec86b8870d75.tar.gz rust-6d3acf5129767db78a3d9d62e814ec86b8870d75.zip | |
Auto merge of #76928 - lcnr:opaque-types-cache, r=tmandry
cache types during normalization
partially fixes #75992
reduces the following test from 14 to 3 seconds locally.
cc `@Mark-Simulacrum` would it make sense to add that test to `perf`?
```rust
#![recursion_limit="2048"]
#![type_length_limit="112457564"]
pub async fn h0(v: &String, x: &u64) { println!("{} {}", v, x) }
pub async fn h1(v: &String, x: &u64) { h0(v, x).await }
pub async fn h2(v: &String, x: &u64) { h1(v, x).await }
pub async fn h3(v: &String, x: &u64) { h2(v, x).await }
pub async fn h4(v: &String, x: &u64) { h3(v, x).await }
pub async fn h5(v: &String, x: &u64) { h4(v, x).await }
pub async fn h6(v: &String, x: &u64) { h5(v, x).await }
pub async fn h7(v: &String, x: &u64) { h6(v, x).await }
pub async fn h8(v: &String, x: &u64) { h7(v, x).await }
pub async fn h9(v: &String, x: &u64) { h8(v, x).await }
pub async fn h10(v: &String, x: &u64) { h9(v, x).await }
pub async fn h11(v: &String, x: &u64) { h10(v, x).await }
pub async fn h12(v: &String, x: &u64) { h11(v, x).await }
pub async fn h13(v: &String, x: &u64) { h12(v, x).await }
pub async fn h14(v: &String, x: &u64) { h13(v, x).await }
pub async fn h15(v: &String, x: &u64) { h14(v, x).await }
pub async fn h16(v: &String, x: &u64) { h15(v, x).await }
pub async fn h17(v: &String, x: &u64) { h16(v, x).await }
pub async fn h18(v: &String, x: &u64) { h17(v, x).await }
pub async fn h19(v: &String, x: &u64) { h18(v, x).await }
macro_rules! async_recursive {
(29, $inner:expr) => { async { async_recursive!(28, $inner) }.await };
(28, $inner:expr) => { async { async_recursive!(27, $inner) }.await };
(27, $inner:expr) => { async { async_recursive!(26, $inner) }.await };
(26, $inner:expr) => { async { async_recursive!(25, $inner) }.await };
(25, $inner:expr) => { async { async_recursive!(24, $inner) }.await };
(24, $inner:expr) => { async { async_recursive!(23, $inner) }.await };
(23, $inner:expr) => { async { async_recursive!(22, $inner) }.await };
(22, $inner:expr) => { async { async_recursive!(21, $inner) }.await };
(21, $inner:expr) => { async { async_recursive!(20, $inner) }.await };
(20, $inner:expr) => { async { async_recursive!(19, $inner) }.await };
(19, $inner:expr) => { async { async_recursive!(18, $inner) }.await };
(18, $inner:expr) => { async { async_recursive!(17, $inner) }.await };
(17, $inner:expr) => { async { async_recursive!(16, $inner) }.await };
(16, $inner:expr) => { async { async_recursive!(15, $inner) }.await };
(15, $inner:expr) => { async { async_recursive!(14, $inner) }.await };
(14, $inner:expr) => { async { async_recursive!(13, $inner) }.await };
(13, $inner:expr) => { async { async_recursive!(12, $inner) }.await };
(12, $inner:expr) => { async { async_recursive!(11, $inner) }.await };
(11, $inner:expr) => { async { async_recursive!(10, $inner) }.await };
(10, $inner:expr) => { async { async_recursive!(9, $inner) }.await };
(9, $inner:expr) => { async { async_recursive!(8, $inner) }.await };
(8, $inner:expr) => { async { async_recursive!(7, $inner) }.await };
(7, $inner:expr) => { async { async_recursive!(6, $inner) }.await };
(6, $inner:expr) => { async { async_recursive!(5, $inner) }.await };
(5, $inner:expr) => { async { async_recursive!(4, $inner) }.await };
(4, $inner:expr) => { async { async_recursive!(3, $inner) }.await };
(3, $inner:expr) => { async { async_recursive!(2, $inner) }.await };
(2, $inner:expr) => { async { async_recursive!(1, $inner) }.await };
(1, $inner:expr) => { async { async_recursive!(0, $inner) }.await };
(0, $inner:expr) => { async { h19(&String::from("owo"), &0).await; $inner }.await };
}
async fn f() {
async_recursive!(14, println!("hello"));
}
fn main() {
let _ = f();
}
```
r? `@eddyb` requires a perf run.
Diffstat (limited to 'compiler/rustc_data_structures')
| -rw-r--r-- | compiler/rustc_data_structures/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_data_structures/src/lib.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_data_structures/src/mini_map.rs | 61 |
3 files changed, 69 insertions, 5 deletions
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index bf75fc96f1f..caaf7c0c3c2 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" doctest = false [dependencies] +arrayvec = { version = "0.5.1", default-features = false } ena = "0.14" indexmap = "1.5.1" tracing = "0.1" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 8dafcdf3bc6..1f977805f5e 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -88,25 +88,27 @@ pub mod sorted_map; pub mod stable_set; #[macro_use] pub mod stable_hasher; +mod atomic_ref; +pub mod fingerprint; +pub mod profiling; pub mod sharded; pub mod stack; pub mod sync; pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; -pub use ena::undo_log; -pub use ena::unify; -mod atomic_ref; -pub mod fingerprint; -pub mod profiling; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; +pub mod mini_map; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; +pub use ena::undo_log; +pub use ena::unify; + pub struct OnDrop<F: Fn()>(pub F); impl<F: Fn()> OnDrop<F> { diff --git a/compiler/rustc_data_structures/src/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs new file mode 100644 index 00000000000..cd3e949d383 --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_map.rs @@ -0,0 +1,61 @@ +use crate::fx::FxHashMap; +use arrayvec::ArrayVec; + +use std::hash::Hash; + +/// Small-storage-optimized implementation of a map +/// made specifically for caching results. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashMap` when that length is exceeded. +pub enum MiniMap<K, V> { + Array(ArrayVec<[(K, V); 8]>), + Map(FxHashMap<K, V>), +} + +impl<K: Eq + Hash, V> MiniMap<K, V> { + /// Creates an empty `MiniMap`. + pub fn new() -> Self { + MiniMap::Array(ArrayVec::new()) + } + + /// Inserts or updates value in the map. + pub fn insert(&mut self, key: K, value: V) { + match self { + MiniMap::Array(array) => { + for pair in array.iter_mut() { + if pair.0 == key { + pair.1 = value; + return; + } + } + if let Err(error) = array.try_push((key, value)) { + let mut map: FxHashMap<K, V> = array.drain(..).collect(); + let (key, value) = error.element(); + map.insert(key, value); + *self = MiniMap::Map(map); + } + } + MiniMap::Map(map) => { + map.insert(key, value); + } + } + } + + /// Return value by key if any. + pub fn get(&self, key: &K) -> Option<&V> { + match self { + MiniMap::Array(array) => { + for pair in array { + if pair.0 == *key { + return Some(&pair.1); + } + } + return None; + } + MiniMap::Map(map) => { + return map.get(key); + } + } + } +} |
