From aeb7d64dca25b0271fe2e3769aa7f390714bfb7c Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 28 Jul 2024 01:08:09 +0300 Subject: [PATCH] bootstrap: use `internment` instead of hand-rolled interning --- src/bootstrap/Cargo.lock | 64 ++++++++ src/bootstrap/Cargo.toml | 1 + src/bootstrap/src/core/config/config.rs | 30 ++-- src/bootstrap/src/utils/cache.rs | 190 +----------------------- 4 files changed, 82 insertions(+), 203 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 952db063636e0..69f60ff9ed4da 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +23,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anstyle" version = "1.0.8" @@ -44,6 +62,7 @@ dependencies = [ "fd-lock", "home", "ignore", + "internment", "junction", "libc", "object", @@ -275,6 +294,16 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "heck" version = "0.5.0" @@ -306,6 +335,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "internment" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f54d755e2513c46a29d3c06fed25aa5d2008252469266055797f331a71aa42" +dependencies = [ + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.11" @@ -386,6 +424,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" + [[package]] name = "opener" version = "0.5.2" @@ -836,3 +880,23 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1959d0a9662da..0d8bf5865ece4 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 77e0ece31047f..bc1a399d7562e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -22,7 +22,7 @@ use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; -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}; @@ -447,15 +447,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); @@ -482,18 +488,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 { @@ -553,7 +555,7 @@ impl fmt::Debug for TargetSelection { impl PartialEq<&str> for TargetSelection { fn eq(&self, other: &&str) -> bool { - self.triple == *other + &*self.triple == *other } } @@ -561,7 +563,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() } } @@ -2072,7 +2074,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 3f78b04d44aa3..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<'a> PartialEq<&'a str> for Interned { - fn eq(&self, other: &&str) -> bool { - **self == **other - } -} -impl<'a, T> PartialEq<&'a Interned> for Interned { - fn eq(&self, other: &&Self) -> bool { - self.0 == other.0 - } -} -impl<'a, T> PartialEq> for &'a 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,