Skip to content

Commit ca64da2

Browse files
committed
bootstrap: use internment instead of hand-rolled interning
1 parent fbccf50 commit ca64da2

File tree

4 files changed

+74
-203
lines changed

4 files changed

+74
-203
lines changed

src/bootstrap/Cargo.lock

+57
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22
# It is not intended for manual editing.
33
version = 3
44

5+
[[package]]
6+
name = "ahash"
7+
version = "0.8.11"
8+
source = "registry+https://github.com/rust-lang/crates.io-index"
9+
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
10+
dependencies = [
11+
"cfg-if",
12+
"once_cell",
13+
"version_check",
14+
"zerocopy",
15+
]
16+
517
[[package]]
618
name = "aho-corasick"
719
version = "1.1.2"
@@ -11,6 +23,12 @@ dependencies = [
1123
"memchr",
1224
]
1325

26+
[[package]]
27+
name = "allocator-api2"
28+
version = "0.2.18"
29+
source = "registry+https://github.com/rust-lang/crates.io-index"
30+
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
31+
1432
[[package]]
1533
name = "anstyle"
1634
version = "1.0.4"
@@ -50,6 +68,7 @@ dependencies = [
5068
"fd-lock",
5169
"home",
5270
"ignore",
71+
"internment",
5372
"junction",
5473
"libc",
5574
"object",
@@ -278,6 +297,16 @@ dependencies = [
278297
"regex-syntax",
279298
]
280299

300+
[[package]]
301+
name = "hashbrown"
302+
version = "0.14.5"
303+
source = "registry+https://github.com/rust-lang/crates.io-index"
304+
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
305+
dependencies = [
306+
"ahash",
307+
"allocator-api2",
308+
]
309+
281310
[[package]]
282311
name = "heck"
283312
version = "0.4.1"
@@ -309,6 +338,14 @@ dependencies = [
309338
"winapi-util",
310339
]
311340

341+
[[package]]
342+
name = "internment"
343+
version = "0.8.4"
344+
source = "git+https://github.com/droundy/internment.git#8a5feb354d023a7c69f3889e9e737099ec0e4ea7"
345+
dependencies = [
346+
"hashbrown",
347+
]
348+
312349
[[package]]
313350
name = "itoa"
314351
version = "1.0.10"
@@ -759,3 +796,23 @@ name = "yansi"
759796
version = "0.5.1"
760797
source = "registry+https://github.com/rust-lang/crates.io-index"
761798
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
799+
800+
[[package]]
801+
name = "zerocopy"
802+
version = "0.7.35"
803+
source = "registry+https://github.com/rust-lang/crates.io-index"
804+
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
805+
dependencies = [
806+
"zerocopy-derive",
807+
]
808+
809+
[[package]]
810+
name = "zerocopy-derive"
811+
version = "0.7.35"
812+
source = "registry+https://github.com/rust-lang/crates.io-index"
813+
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
814+
dependencies = [
815+
"proc-macro2",
816+
"quote",
817+
"syn",
818+
]

src/bootstrap/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ clap = { version = "4.4", default-features = false, features = ["std", "usage",
4545
clap_complete = "4.4"
4646
fd-lock = "4.0"
4747
home = "0.5"
48+
internment = { git = "https://github.com/droundy/internment.git" } # internment = "0.8.5"
4849
ignore = "0.4"
4950
libc = "0.2"
5051
object = { version = "0.32", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }

src/bootstrap/src/core/config/config.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::sync::OnceLock;
1818
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
1919
use crate::core::build_steps::llvm;
2020
use crate::core::config::flags::{Color, Flags, Warnings};
21-
use crate::utils::cache::{Interned, INTERNER};
21+
use crate::utils::cache::Interned;
2222
use crate::utils::channel::{self, GitInfo};
2323
use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
2424
use build_helper::exit;
@@ -437,15 +437,21 @@ impl std::str::FromStr for RustcLto {
437437
}
438438
}
439439

440-
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
440+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
441441
// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy.
442442
// Making !Copy is highly nontrivial!
443443
pub struct TargetSelection {
444-
pub triple: Interned<String>,
445-
file: Option<Interned<String>>,
444+
pub triple: Interned<str>,
445+
file: Option<Interned<str>>,
446446
synthetic: bool,
447447
}
448448

449+
impl Default for TargetSelection {
450+
fn default() -> Self {
451+
Self { triple: "".into(), file: Default::default(), synthetic: Default::default() }
452+
}
453+
}
454+
449455
/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
450456
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
451457
pub struct TargetSelectionList(Vec<TargetSelection>);
@@ -472,18 +478,14 @@ impl TargetSelection {
472478
(selection, None)
473479
};
474480

475-
let triple = INTERNER.intern_str(triple);
476-
let file = file.map(|f| INTERNER.intern_str(f));
481+
let triple: Interned<str> = triple.into();
482+
let file: Option<Interned<str>> = file.map(|f| f.into());
477483

478484
Self { triple, file, synthetic: false }
479485
}
480486

481487
pub fn create_synthetic(triple: &str, file: &str) -> Self {
482-
Self {
483-
triple: INTERNER.intern_str(triple),
484-
file: Some(INTERNER.intern_str(file)),
485-
synthetic: true,
486-
}
488+
Self { triple: triple.into(), file: Some(file.into()), synthetic: true }
487489
}
488490

489491
pub fn rustc_target_arg(&self) -> &str {
@@ -534,7 +536,7 @@ impl fmt::Debug for TargetSelection {
534536

535537
impl PartialEq<&str> for TargetSelection {
536538
fn eq(&self, other: &&str) -> bool {
537-
self.triple == *other
539+
&*self.triple == *other
538540
}
539541
}
540542

@@ -2014,7 +2016,7 @@ impl Config {
20142016
// thus, disabled
20152017
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
20162018
// when the config sets `rust.lld = false`
2017-
if config.build.triple == "x86_64-unknown-linux-gnu"
2019+
if &*config.build.triple == "x86_64-unknown-linux-gnu"
20182020
&& config.hosts == [config.build]
20192021
&& (config.channel == "dev" || config.channel == "nightly")
20202022
{

src/bootstrap/src/utils/cache.rs

+1-190
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,10 @@
11
use std::any::{Any, TypeId};
2-
use std::borrow::Borrow;
32
use std::cell::RefCell;
4-
use std::cmp::Ordering;
53
use std::collections::HashMap;
6-
use std::fmt;
7-
use std::hash::{Hash, Hasher};
8-
use std::marker::PhantomData;
9-
use std::mem;
10-
use std::ops::Deref;
11-
use std::path::PathBuf;
12-
use std::sync::{LazyLock, Mutex};
134

145
use crate::core::builder::Step;
156

16-
pub struct Interned<T>(usize, PhantomData<*const T>);
17-
18-
impl<T: Internable + Default> Default for Interned<T> {
19-
fn default() -> Self {
20-
T::default().intern()
21-
}
22-
}
23-
24-
impl<T> Copy for Interned<T> {}
25-
impl<T> Clone for Interned<T> {
26-
fn clone(&self) -> Interned<T> {
27-
*self
28-
}
29-
}
30-
31-
impl<T> PartialEq for Interned<T> {
32-
fn eq(&self, other: &Self) -> bool {
33-
self.0 == other.0
34-
}
35-
}
36-
impl<T> Eq for Interned<T> {}
37-
38-
impl PartialEq<str> for Interned<String> {
39-
fn eq(&self, other: &str) -> bool {
40-
*self == other
41-
}
42-
}
43-
impl<'a> PartialEq<&'a str> for Interned<String> {
44-
fn eq(&self, other: &&str) -> bool {
45-
**self == **other
46-
}
47-
}
48-
impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
49-
fn eq(&self, other: &&Self) -> bool {
50-
self.0 == other.0
51-
}
52-
}
53-
impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
54-
fn eq(&self, other: &Interned<T>) -> bool {
55-
self.0 == other.0
56-
}
57-
}
58-
59-
unsafe impl<T> Send for Interned<T> {}
60-
unsafe impl<T> Sync for Interned<T> {}
61-
62-
impl fmt::Display for Interned<String> {
63-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64-
let s: &str = self;
65-
f.write_str(s)
66-
}
67-
}
68-
69-
impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
70-
where
71-
Self: Deref<Target = U>,
72-
{
73-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74-
let s: &U = self;
75-
f.write_fmt(format_args!("{s:?}"))
76-
}
77-
}
78-
79-
impl<T: Internable + Hash> Hash for Interned<T> {
80-
fn hash<H: Hasher>(&self, state: &mut H) {
81-
let l = T::intern_cache().lock().unwrap();
82-
l.get(*self).hash(state)
83-
}
84-
}
85-
86-
impl<T: Internable + Deref> Deref for Interned<T> {
87-
type Target = T::Target;
88-
fn deref(&self) -> &Self::Target {
89-
let l = T::intern_cache().lock().unwrap();
90-
unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) }
91-
}
92-
}
93-
94-
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
95-
fn as_ref(&self) -> &U {
96-
let l = T::intern_cache().lock().unwrap();
97-
unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) }
98-
}
99-
}
100-
101-
impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
102-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103-
let l = T::intern_cache().lock().unwrap();
104-
l.get(*self).partial_cmp(l.get(*other))
105-
}
106-
}
107-
108-
impl<T: Internable + Ord> Ord for Interned<T> {
109-
fn cmp(&self, other: &Self) -> Ordering {
110-
let l = T::intern_cache().lock().unwrap();
111-
l.get(*self).cmp(l.get(*other))
112-
}
113-
}
114-
115-
struct TyIntern<T: Clone + Eq> {
116-
items: Vec<T>,
117-
set: HashMap<T, Interned<T>>,
118-
}
119-
120-
impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
121-
fn default() -> Self {
122-
TyIntern { items: Vec::new(), set: Default::default() }
123-
}
124-
}
125-
126-
impl<T: Hash + Clone + Eq> TyIntern<T> {
127-
fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
128-
where
129-
B: Eq + Hash + ToOwned<Owned = T> + ?Sized,
130-
T: Borrow<B>,
131-
{
132-
if let Some(i) = self.set.get(item) {
133-
return *i;
134-
}
135-
let item = item.to_owned();
136-
let interned = Interned(self.items.len(), PhantomData::<*const T>);
137-
self.set.insert(item.clone(), interned);
138-
self.items.push(item);
139-
interned
140-
}
141-
142-
fn intern(&mut self, item: T) -> Interned<T> {
143-
if let Some(i) = self.set.get(&item) {
144-
return *i;
145-
}
146-
let interned = Interned(self.items.len(), PhantomData::<*const T>);
147-
self.set.insert(item.clone(), interned);
148-
self.items.push(item);
149-
interned
150-
}
151-
152-
fn get(&self, i: Interned<T>) -> &T {
153-
&self.items[i.0]
154-
}
155-
}
156-
157-
#[derive(Default)]
158-
pub struct Interner {
159-
strs: Mutex<TyIntern<String>>,
160-
paths: Mutex<TyIntern<PathBuf>>,
161-
lists: Mutex<TyIntern<Vec<String>>>,
162-
}
163-
164-
trait Internable: Clone + Eq + Hash + 'static {
165-
fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
166-
167-
fn intern(self) -> Interned<Self> {
168-
Self::intern_cache().lock().unwrap().intern(self)
169-
}
170-
}
171-
172-
impl Internable for String {
173-
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
174-
&INTERNER.strs
175-
}
176-
}
177-
178-
impl Internable for PathBuf {
179-
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
180-
&INTERNER.paths
181-
}
182-
}
183-
184-
impl Internable for Vec<String> {
185-
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
186-
&INTERNER.lists
187-
}
188-
}
189-
190-
impl Interner {
191-
pub fn intern_str(&self, s: &str) -> Interned<String> {
192-
self.strs.lock().unwrap().intern_borrow(s)
193-
}
194-
}
195-
196-
pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
7+
pub type Interned<T> = internment::Intern<T>;
1978

1989
/// This is essentially a `HashMap` which allows storing any type in its input and
19910
/// any type in its output. It is a write-once cache; values are never evicted,

0 commit comments

Comments
 (0)