22//! allows bidirectional lookup; i.e., given a value, one can easily find the
33//! type, and vice versa.
44
5- use std:: hash:: { Hash , Hasher } ;
5+ use std:: hash:: { BuildHasher , Hash , Hasher } ;
66use std:: { fmt, str} ;
77
88use rustc_arena:: DroplessArena ;
9- use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
9+ use rustc_data_structures:: fx:: FxBuildHasher ;
10+ use rustc_data_structures:: hash_table:: { Entry , HashTable } ;
1011use rustc_data_structures:: stable_hash:: { StableCompare , StableHash , StableHashCtxt , StableHasher } ;
1112use rustc_data_structures:: sync:: Lock ;
1213use rustc_macros:: { Decodable , Encodable , StableHash , symbols} ;
@@ -2712,32 +2713,43 @@ pub(crate) struct Interner(Lock<InternerInner>);
27122713// between `Interner`s.
27132714struct InternerInner {
27142715 arena : DroplessArena ,
2715- byte_strs : FxIndexSet < & ' static [ u8 ] > ,
2716+ indices : HashTable < ( & ' static [ u8 ] , u32 ) > ,
2717+ byte_strs : Vec < & ' static [ u8 ] > ,
27162718}
27172719
27182720impl Interner {
27192721 // These arguments are `&str`, but because of the sharing, we are
27202722 // effectively pre-interning all these strings for both `Symbol` and
27212723 // `ByteSymbol`.
27222724 fn prefill ( init : & [ & ' static str ] , extra : & [ & ' static str ] ) -> Self {
2723- let byte_strs = FxIndexSet :: from_iter (
2724- init . iter ( ) . copied ( ) . chain ( extra . iter ( ) . copied ( ) ) . map ( |str| str . as_bytes ( ) ) ,
2725- ) ;
2725+ let values = init . iter ( ) . copied ( ) . chain ( extra . iter ( ) . copied ( ) ) . map ( |str| str . as_bytes ( ) ) ;
2726+ let ( size_hint , _ ) = values . size_hint ( ) ;
2727+ let mut conflicting_values : Vec < & [ u8 ] > = Vec :: new ( ) ;
27262728
2727- // The order in which duplicates are reported is irrelevant.
2728- #[ expect( rustc:: potential_query_instability) ]
2729- if byte_strs. len ( ) != init. len ( ) + extra. len ( ) {
2729+ let mut indices: HashTable < ( & ' static [ u8 ] , u32 ) > = HashTable :: with_capacity ( size_hint) ;
2730+ let hasher = FxBuildHasher :: default ( ) ;
2731+
2732+ let mut byte_strs: Vec < & ' static [ u8 ] > = Vec :: with_capacity ( size_hint) ;
2733+
2734+ for v in values {
2735+ match indices. entry ( hasher. hash_one ( & v) , |& ( s, _) | s == v, |& ( s, _) | hasher. hash_one ( s) )
2736+ {
2737+ Entry :: Occupied ( v) => conflicting_values. push ( v. get ( ) . 0 ) ,
2738+ Entry :: Vacant ( view) => {
2739+ view. insert ( ( v, byte_strs. len ( ) as u32 ) ) ;
2740+ byte_strs. push ( v) ;
2741+ }
2742+ }
2743+ }
2744+
2745+ if conflicting_values. len ( ) != 0 {
27302746 panic ! (
27312747 "duplicate symbols in the rustc symbol list and the extra symbols added by the driver: {:?}" ,
2732- FxHashSet :: intersection(
2733- & init. iter( ) . copied( ) . collect( ) ,
2734- & extra. iter( ) . copied( ) . collect( ) ,
2735- )
2736- . collect:: <Vec <_>>( )
2748+ conflicting_values
27372749 )
27382750 }
27392751
2740- Interner ( Lock :: new ( InternerInner { arena : Default :: default ( ) , byte_strs } ) )
2752+ Interner ( Lock :: new ( InternerInner { arena : Default :: default ( ) , indices , byte_strs } ) )
27412753 }
27422754
27432755 fn intern_str ( & self , str : & str ) -> Symbol {
@@ -2750,24 +2762,29 @@ impl Interner {
27502762
27512763 #[ inline]
27522764 fn intern_inner ( & self , byte_str : & [ u8 ] ) -> u32 {
2753- let mut inner = self . 0 . lock ( ) ;
2754- if let Some ( idx) = inner. byte_strs . get_index_of ( byte_str) {
2755- return idx as u32 ;
2756- }
2757-
2758- let byte_str: & [ u8 ] = inner. arena . alloc_slice ( byte_str) ;
2759-
2760- // SAFETY: we can extend the arena allocation to `'static` because we
2761- // only access these while the arena is still alive.
2762- let byte_str: & ' static [ u8 ] = unsafe { & * ( byte_str as * const [ u8 ] ) } ;
2763-
2764- // This second hash table lookup can be avoided by using `RawEntryMut`,
2765- // but this code path isn't hot enough for it to be worth it. See
2766- // #91445 for details.
2767- let ( idx, is_new) = inner. byte_strs . insert_full ( byte_str) ;
2768- debug_assert ! ( is_new) ; // due to the get_index_of check above
2769-
2770- idx as u32
2765+ let hasher = FxBuildHasher :: default ( ) ;
2766+ let hash_of_byte_str = hasher. hash_one ( byte_str) ;
2767+
2768+ self . 0 . with_lock ( |inner| {
2769+ match inner. indices . entry (
2770+ hash_of_byte_str,
2771+ |& ( s, _) | s == byte_str,
2772+ |& ( s, _) | hasher. hash_one ( s) ,
2773+ ) {
2774+ Entry :: Occupied ( v) => v. get ( ) . 1 ,
2775+ Entry :: Vacant ( view) => {
2776+ let byte_str: & [ u8 ] = inner. arena . alloc_slice ( byte_str) ;
2777+
2778+ // SAFETY: we can extend the arena allocation to `'static` because we
2779+ // only access these while the arena is still alive.
2780+ let byte_str: & ' static [ u8 ] = unsafe { & * ( byte_str as * const [ u8 ] ) } ;
2781+ let idx = inner. byte_strs . len ( ) as u32 ;
2782+ view. insert ( ( byte_str, idx) ) ;
2783+ inner. byte_strs . push ( byte_str) ;
2784+ idx
2785+ }
2786+ }
2787+ } )
27712788 }
27722789
27732790 /// Get the symbol as a string.
@@ -2787,7 +2804,7 @@ impl Interner {
27872804 }
27882805
27892806 fn get_inner ( & self , index : usize ) -> & [ u8 ] {
2790- self . 0 . lock ( ) . byte_strs . get_index ( index) . unwrap ( )
2807+ self . 0 . with_lock ( |inner| inner . byte_strs [ index] )
27912808 }
27922809}
27932810
0 commit comments