diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index efcac4f0953d0..be917c89cd43d 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611cc2ae7d2e242c457e4be7f97036b8ad9ca152b499f53faf99b1ed8fc2553f" + [[package]] name = "anstyle" version = "1.0.8" @@ -44,6 +50,7 @@ dependencies = [ "fd-lock", "home", "ignore", + "internment", "junction", "libc", "object", @@ -219,6 +226,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.9" @@ -252,6 +265,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "generic-array" version = "0.14.7" @@ -275,6 +294,17 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heck" version = "0.5.0" @@ -306,6 +336,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "internment" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636d4b0f6a39fd684effe2a73f5310df16a3fa7954c26d36833e98f44d1977a2" +dependencies = [ + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.11" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ba505089a000a..7f3954caa35b9 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -45,6 +45,7 @@ clap = { version = "4.4", default-features = false, features = ["std", "usage", clap_complete = "4.4" fd-lock = "4.0" home = "0.5" +internment = "0.8.5" ignore = "0.4" libc = "0.2" object = { version = "0.36.3", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a93038d51d3d0..6530abbc3ebe3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -24,7 +24,7 @@ use crate::core::build_steps::llvm; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::core::download::is_download_ci_available; -use crate::utils::cache::{INTERNER, Interned}; +use crate::utils::cache::Interned; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{self, exe, output, t}; @@ -465,15 +465,21 @@ impl std::str::FromStr for RustcLto { } } -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] // N.B.: This type is used everywhere, and the entire codebase relies on it being Copy. // Making !Copy is highly nontrivial! pub struct TargetSelection { - pub triple: Interned, - file: Option>, + pub triple: Interned, + file: Option>, synthetic: bool, } +impl Default for TargetSelection { + fn default() -> Self { + Self { triple: "".into(), file: Default::default(), synthetic: Default::default() } + } +} + /// Newtype over `Vec` so we can implement custom parsing logic #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct TargetSelectionList(Vec); @@ -500,18 +506,14 @@ impl TargetSelection { (selection, None) }; - let triple = INTERNER.intern_str(triple); - let file = file.map(|f| INTERNER.intern_str(f)); + let triple: Interned = triple.into(); + let file: Option> = file.map(|f| f.into()); Self { triple, file, synthetic: false } } pub fn create_synthetic(triple: &str, file: &str) -> Self { - Self { - triple: INTERNER.intern_str(triple), - file: Some(INTERNER.intern_str(file)), - synthetic: true, - } + Self { triple: triple.into(), file: Some(file.into()), synthetic: true } } pub fn rustc_target_arg(&self) -> &str { @@ -571,7 +573,7 @@ impl fmt::Debug for TargetSelection { impl PartialEq<&str> for TargetSelection { fn eq(&self, other: &&str) -> bool { - self.triple == *other + &*self.triple == *other } } @@ -579,7 +581,7 @@ impl PartialEq<&str> for TargetSelection { // This impl makes it more ergonomics to use them as such. impl AsRef for TargetSelection { fn as_ref(&self) -> &Path { - self.triple.as_ref() + (*self.triple).as_ref() } } @@ -2119,7 +2121,7 @@ impl Config { // thus, disabled // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. // when the config sets `rust.lld = false` - if config.build.triple == "x86_64-unknown-linux-gnu" + if &*config.build.triple == "x86_64-unknown-linux-gnu" && config.hosts == [config.build] && (config.channel == "dev" || config.channel == "nightly") { diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 29342cc5a2c5b..ea3a4180dd736 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -1,198 +1,10 @@ use std::any::{Any, TypeId}; -use std::borrow::Borrow; use std::cell::RefCell; -use std::cmp::Ordering; use std::collections::HashMap; -use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; -use std::ops::Deref; -use std::path::PathBuf; -use std::sync::{LazyLock, Mutex}; -use std::{fmt, mem}; use crate::core::builder::Step; -pub struct Interned(usize, PhantomData<*const T>); - -impl Default for Interned { - fn default() -> Self { - T::default().intern() - } -} - -impl Copy for Interned {} -impl Clone for Interned { - fn clone(&self) -> Interned { - *self - } -} - -impl PartialEq for Interned { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} -impl Eq for Interned {} - -impl PartialEq for Interned { - fn eq(&self, other: &str) -> bool { - *self == other - } -} -impl PartialEq<&str> for Interned { - fn eq(&self, other: &&str) -> bool { - **self == **other - } -} -impl PartialEq<&Interned> for Interned { - fn eq(&self, other: &&Self) -> bool { - self.0 == other.0 - } -} -impl PartialEq> for &Interned { - fn eq(&self, other: &Interned) -> bool { - self.0 == other.0 - } -} - -unsafe impl Send for Interned {} -unsafe impl Sync for Interned {} - -impl fmt::Display for Interned { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s: &str = self; - f.write_str(s) - } -} - -impl fmt::Debug for Interned -where - Self: Deref, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s: &U = self; - f.write_fmt(format_args!("{s:?}")) - } -} - -impl Hash for Interned { - fn hash(&self, state: &mut H) { - let l = T::intern_cache().lock().unwrap(); - l.get(*self).hash(state) - } -} - -impl Deref for Interned { - type Target = T::Target; - fn deref(&self) -> &Self::Target { - let l = T::intern_cache().lock().unwrap(); - unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) } - } -} - -impl, U: ?Sized> AsRef for Interned { - fn as_ref(&self) -> &U { - let l = T::intern_cache().lock().unwrap(); - unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) } - } -} - -impl PartialOrd for Interned { - fn partial_cmp(&self, other: &Self) -> Option { - let l = T::intern_cache().lock().unwrap(); - l.get(*self).partial_cmp(l.get(*other)) - } -} - -impl Ord for Interned { - fn cmp(&self, other: &Self) -> Ordering { - let l = T::intern_cache().lock().unwrap(); - l.get(*self).cmp(l.get(*other)) - } -} - -struct TyIntern { - items: Vec, - set: HashMap>, -} - -impl Default for TyIntern { - fn default() -> Self { - TyIntern { items: Vec::new(), set: Default::default() } - } -} - -impl TyIntern { - fn intern_borrow(&mut self, item: &B) -> Interned - where - B: Eq + Hash + ToOwned + ?Sized, - T: Borrow, - { - if let Some(i) = self.set.get(item) { - return *i; - } - let item = item.to_owned(); - let interned = Interned(self.items.len(), PhantomData::<*const T>); - self.set.insert(item.clone(), interned); - self.items.push(item); - interned - } - - fn intern(&mut self, item: T) -> Interned { - if let Some(i) = self.set.get(&item) { - return *i; - } - let interned = Interned(self.items.len(), PhantomData::<*const T>); - self.set.insert(item.clone(), interned); - self.items.push(item); - interned - } - - fn get(&self, i: Interned) -> &T { - &self.items[i.0] - } -} - -#[derive(Default)] -pub struct Interner { - strs: Mutex>, - paths: Mutex>, - lists: Mutex>>, -} - -trait Internable: Clone + Eq + Hash + 'static { - fn intern_cache() -> &'static Mutex>; - - fn intern(self) -> Interned { - Self::intern_cache().lock().unwrap().intern(self) - } -} - -impl Internable for String { - fn intern_cache() -> &'static Mutex> { - &INTERNER.strs - } -} - -impl Internable for PathBuf { - fn intern_cache() -> &'static Mutex> { - &INTERNER.paths - } -} - -impl Internable for Vec { - fn intern_cache() -> &'static Mutex> { - &INTERNER.lists - } -} - -impl Interner { - pub fn intern_str(&self, s: &str) -> Interned { - self.strs.lock().unwrap().intern_borrow(s) - } -} - -pub static INTERNER: LazyLock = LazyLock::new(Interner::default); +pub type Interned = internment::Intern; /// This is essentially a `HashMap` which allows storing any type in its input and /// any type in its output. It is a write-once cache; values are never evicted,