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} ;
@@ -2744,32 +2745,43 @@ pub(crate) struct Interner(Lock<InternerInner>);
27442745// between `Interner`s.
27452746struct InternerInner {
27462747 arena : DroplessArena ,
2747- byte_strs : FxIndexSet < & ' static [ u8 ] > ,
2748+ indices : HashTable < ( & ' static [ u8 ] , u32 ) > ,
2749+ byte_strs : Vec < & ' static [ u8 ] > ,
27482750}
27492751
27502752impl Interner {
27512753 // These arguments are `&str`, but because of the sharing, we are
27522754 // effectively pre-interning all these strings for both `Symbol` and
27532755 // `ByteSymbol`.
27542756 fn prefill ( init : & [ & ' static str ] , extra : & [ & ' static str ] ) -> Self {
2755- let byte_strs = FxIndexSet :: from_iter (
2756- init . iter ( ) . copied ( ) . chain ( extra . iter ( ) . copied ( ) ) . map ( |str| str . as_bytes ( ) ) ,
2757- ) ;
2757+ let values = init . iter ( ) . copied ( ) . chain ( extra . iter ( ) . copied ( ) ) . map ( |str| str . as_bytes ( ) ) ;
2758+ let ( size_hint , _ ) = values . size_hint ( ) ;
2759+ let mut conflicting_values : Vec < & [ u8 ] > = Vec :: new ( ) ;
27582760
2759- // The order in which duplicates are reported is irrelevant.
2760- #[ expect( rustc:: potential_query_instability) ]
2761- if byte_strs. len ( ) != init. len ( ) + extra. len ( ) {
2761+ let mut indices: HashTable < ( & ' static [ u8 ] , u32 ) > = HashTable :: with_capacity ( size_hint) ;
2762+ let hasher = FxBuildHasher :: default ( ) ;
2763+
2764+ let mut byte_strs: Vec < & ' static [ u8 ] > = Vec :: with_capacity ( size_hint) ;
2765+
2766+ for v in values {
2767+ match indices. entry ( hasher. hash_one ( & v) , |& ( s, _) | s == v, |& ( s, _) | hasher. hash_one ( s) )
2768+ {
2769+ Entry :: Occupied ( v) => conflicting_values. push ( v. get ( ) . 0 ) ,
2770+ Entry :: Vacant ( view) => {
2771+ view. insert ( ( v, byte_strs. len ( ) as u32 ) ) ;
2772+ byte_strs. push ( v) ;
2773+ }
2774+ }
2775+ }
2776+
2777+ if conflicting_values. len ( ) != 0 {
27622778 panic ! (
27632779 "duplicate symbols in the rustc symbol list and the extra symbols added by the driver: {:?}" ,
2764- FxHashSet :: intersection(
2765- & init. iter( ) . copied( ) . collect( ) ,
2766- & extra. iter( ) . copied( ) . collect( ) ,
2767- )
2768- . collect:: <Vec <_>>( )
2780+ conflicting_values
27692781 )
27702782 }
27712783
2772- Interner ( Lock :: new ( InternerInner { arena : Default :: default ( ) , byte_strs } ) )
2784+ Interner ( Lock :: new ( InternerInner { arena : Default :: default ( ) , indices , byte_strs } ) )
27732785 }
27742786
27752787 fn intern_str ( & self , str : & str ) -> Symbol {
@@ -2782,24 +2794,29 @@ impl Interner {
27822794
27832795 #[ inline]
27842796 fn intern_inner ( & self , byte_str : & [ u8 ] ) -> u32 {
2785- let mut inner = self . 0 . lock ( ) ;
2786- if let Some ( idx) = inner. byte_strs . get_index_of ( byte_str) {
2787- return idx as u32 ;
2788- }
2789-
2790- let byte_str: & [ u8 ] = inner. arena . alloc_slice ( byte_str) ;
2791-
2792- // SAFETY: we can extend the arena allocation to `'static` because we
2793- // only access these while the arena is still alive.
2794- let byte_str: & ' static [ u8 ] = unsafe { & * ( byte_str as * const [ u8 ] ) } ;
2795-
2796- // This second hash table lookup can be avoided by using `RawEntryMut`,
2797- // but this code path isn't hot enough for it to be worth it. See
2798- // #91445 for details.
2799- let ( idx, is_new) = inner. byte_strs . insert_full ( byte_str) ;
2800- debug_assert ! ( is_new) ; // due to the get_index_of check above
2801-
2802- idx as u32
2797+ let hasher = FxBuildHasher :: default ( ) ;
2798+ let hash_of_byte_str = hasher. hash_one ( byte_str) ;
2799+
2800+ self . 0 . with_lock ( |inner| {
2801+ match inner. indices . entry (
2802+ hash_of_byte_str,
2803+ |& ( s, _) | s == byte_str,
2804+ |& ( s, _) | hasher. hash_one ( s) ,
2805+ ) {
2806+ Entry :: Occupied ( v) => v. get ( ) . 1 ,
2807+ Entry :: Vacant ( view) => {
2808+ let byte_str: & [ u8 ] = inner. arena . alloc_slice ( byte_str) ;
2809+
2810+ // SAFETY: we can extend the arena allocation to `'static` because we
2811+ // only access these while the arena is still alive.
2812+ let byte_str: & ' static [ u8 ] = unsafe { & * ( byte_str as * const [ u8 ] ) } ;
2813+ let idx = inner. byte_strs . len ( ) as u32 ;
2814+ view. insert ( ( byte_str, idx) ) ;
2815+ inner. byte_strs . push ( byte_str) ;
2816+ idx
2817+ }
2818+ }
2819+ } )
28032820 }
28042821
28052822 /// Get the symbol as a string.
@@ -2819,7 +2836,7 @@ impl Interner {
28192836 }
28202837
28212838 fn get_inner ( & self , index : usize ) -> & [ u8 ] {
2822- self . 0 . lock ( ) . byte_strs . get_index ( index) . unwrap ( )
2839+ self . 0 . with_lock ( |inner| inner . byte_strs [ index] )
28232840 }
28242841}
28252842
0 commit comments