Skip to content

Commit 3f2af36

Browse files
committed
bootstrap: use internment instead of hand-rolled interning
1 parent 4db3d12 commit 3f2af36

File tree

4 files changed

+74
-202
lines changed

4 files changed

+74
-202
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
@@ -22,7 +22,7 @@ use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
2222
use crate::core::build_steps::llvm;
2323
pub use crate::core::config::flags::Subcommand;
2424
use crate::core::config::flags::{Color, Flags, Warnings};
25-
use crate::utils::cache::{Interned, INTERNER};
25+
use crate::utils::cache::Interned;
2626
use crate::utils::channel::{self, GitInfo};
2727
use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
2828

@@ -435,15 +435,21 @@ impl std::str::FromStr for RustcLto {
435435
}
436436
}
437437

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

447+
impl Default for TargetSelection {
448+
fn default() -> Self {
449+
Self { triple: "".into(), file: Default::default(), synthetic: Default::default() }
450+
}
451+
}
452+
447453
/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
448454
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
449455
pub struct TargetSelectionList(Vec<TargetSelection>);
@@ -470,18 +476,14 @@ impl TargetSelection {
470476
(selection, None)
471477
};
472478

473-
let triple = INTERNER.intern_str(triple);
474-
let file = file.map(|f| INTERNER.intern_str(f));
479+
let triple: Interned<str> = triple.into();
480+
let file: Option<Interned<str>> = file.map(|f| f.into());
475481

476482
Self { triple, file, synthetic: false }
477483
}
478484

479485
pub fn create_synthetic(triple: &str, file: &str) -> Self {
480-
Self {
481-
triple: INTERNER.intern_str(triple),
482-
file: Some(INTERNER.intern_str(file)),
483-
synthetic: true,
484-
}
486+
Self { triple: triple.into(), file: Some(file.into()), synthetic: true }
485487
}
486488

487489
pub fn rustc_target_arg(&self) -> &str {
@@ -532,7 +534,7 @@ impl fmt::Debug for TargetSelection {
532534

533535
impl PartialEq<&str> for TargetSelection {
534536
fn eq(&self, other: &&str) -> bool {
535-
self.triple == *other
537+
&*self.triple == *other
536538
}
537539
}
538540

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

src/bootstrap/src/utils/cache.rs

+1-189
Original file line numberDiff line numberDiff line change
@@ -1,198 +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::hash::{Hash, Hasher};
7-
use std::marker::PhantomData;
8-
use std::ops::Deref;
9-
use std::path::PathBuf;
10-
use std::sync::{LazyLock, Mutex};
11-
use std::{fmt, mem};
124

135
use crate::core::builder::Step;
146

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

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

0 commit comments

Comments
 (0)