Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 585ee32

Browse files
committedSep 14, 2024·
bootstrap: use internment instead of hand-rolled interning
1 parent 5fe0e40 commit 585ee32

File tree

4 files changed

+82
-203
lines changed

4 files changed

+82
-203
lines changed
 

‎src/bootstrap/Cargo.lock

Lines changed: 64 additions & 0 deletions
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.3"
@@ -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.8"
@@ -44,6 +62,7 @@ dependencies = [
4462
"fd-lock",
4563
"home",
4664
"ignore",
65+
"internment",
4766
"junction",
4867
"libc",
4968
"object",
@@ -272,6 +291,16 @@ dependencies = [
272291
"regex-syntax",
273292
]
274293

294+
[[package]]
295+
name = "hashbrown"
296+
version = "0.14.5"
297+
source = "registry+https://github.com/rust-lang/crates.io-index"
298+
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
299+
dependencies = [
300+
"ahash",
301+
"allocator-api2",
302+
]
303+
275304
[[package]]
276305
name = "heck"
277306
version = "0.5.0"
@@ -303,6 +332,15 @@ dependencies = [
303332
"winapi-util",
304333
]
305334

335+
[[package]]
336+
name = "internment"
337+
version = "0.8.5"
338+
source = "registry+https://github.com/rust-lang/crates.io-index"
339+
checksum = "d7f54d755e2513c46a29d3c06fed25aa5d2008252469266055797f331a71aa42"
340+
dependencies = [
341+
"hashbrown",
342+
]
343+
306344
[[package]]
307345
name = "itoa"
308346
version = "1.0.11"
@@ -383,6 +421,12 @@ dependencies = [
383421
"memchr",
384422
]
385423

424+
[[package]]
425+
name = "once_cell"
426+
version = "1.20.0"
427+
source = "registry+https://github.com/rust-lang/crates.io-index"
428+
checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe"
429+
386430
[[package]]
387431
name = "opener"
388432
version = "0.5.2"
@@ -827,3 +871,23 @@ name = "yansi"
827871
version = "0.5.1"
828872
source = "registry+https://github.com/rust-lang/crates.io-index"
829873
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
874+
875+
[[package]]
876+
name = "zerocopy"
877+
version = "0.7.35"
878+
source = "registry+https://github.com/rust-lang/crates.io-index"
879+
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
880+
dependencies = [
881+
"zerocopy-derive",
882+
]
883+
884+
[[package]]
885+
name = "zerocopy-derive"
886+
version = "0.7.35"
887+
source = "registry+https://github.com/rust-lang/crates.io-index"
888+
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
889+
dependencies = [
890+
"proc-macro2",
891+
"quote",
892+
"syn",
893+
]

‎src/bootstrap/Cargo.toml

Lines changed: 1 addition & 0 deletions
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 = "0.8.5"
4849
ignore = "0.4"
4950
libc = "0.2"
5051
object = { version = "0.36.3", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }

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

Lines changed: 16 additions & 14 deletions
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, output, t};
2828

@@ -446,15 +446,21 @@ impl std::str::FromStr for RustcLto {
446446
}
447447
}
448448

449-
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
449+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
450450
// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy.
451451
// Making !Copy is highly nontrivial!
452452
pub struct TargetSelection {
453-
pub triple: Interned<String>,
454-
file: Option<Interned<String>>,
453+
pub triple: Interned<str>,
454+
file: Option<Interned<str>>,
455455
synthetic: bool,
456456
}
457457

458+
impl Default for TargetSelection {
459+
fn default() -> Self {
460+
Self { triple: "".into(), file: Default::default(), synthetic: Default::default() }
461+
}
462+
}
463+
458464
/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
459465
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
460466
pub struct TargetSelectionList(Vec<TargetSelection>);
@@ -481,18 +487,14 @@ impl TargetSelection {
481487
(selection, None)
482488
};
483489

484-
let triple = INTERNER.intern_str(triple);
485-
let file = file.map(|f| INTERNER.intern_str(f));
490+
let triple: Interned<str> = triple.into();
491+
let file: Option<Interned<str>> = file.map(|f| f.into());
486492

487493
Self { triple, file, synthetic: false }
488494
}
489495

490496
pub fn create_synthetic(triple: &str, file: &str) -> Self {
491-
Self {
492-
triple: INTERNER.intern_str(triple),
493-
file: Some(INTERNER.intern_str(file)),
494-
synthetic: true,
495-
}
497+
Self { triple: triple.into(), file: Some(file.into()), synthetic: true }
496498
}
497499

498500
pub fn rustc_target_arg(&self) -> &str {
@@ -552,15 +554,15 @@ impl fmt::Debug for TargetSelection {
552554

553555
impl PartialEq<&str> for TargetSelection {
554556
fn eq(&self, other: &&str) -> bool {
555-
self.triple == *other
557+
&*self.triple == *other
556558
}
557559
}
558560

559561
// Targets are often used as directory names throughout bootstrap.
560562
// This impl makes it more ergonomics to use them as such.
561563
impl AsRef<Path> for TargetSelection {
562564
fn as_ref(&self) -> &Path {
563-
self.triple.as_ref()
565+
(*self.triple).as_ref()
564566
}
565567
}
566568

@@ -2067,7 +2069,7 @@ impl Config {
20672069
// thus, disabled
20682070
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
20692071
// when the config sets `rust.lld = false`
2070-
if config.build.triple == "x86_64-unknown-linux-gnu"
2072+
if &*config.build.triple == "x86_64-unknown-linux-gnu"
20712073
&& config.hosts == [config.build]
20722074
&& (config.channel == "dev" || config.channel == "nightly")
20732075
{

‎src/bootstrap/src/utils/cache.rs

Lines changed: 1 addition & 189 deletions
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)
Please sign in to comment.