@@ -16,8 +16,10 @@ use hygiene::SyntaxContext;
1616use { Span , DUMMY_SP , GLOBALS } ;
1717
1818use rustc_data_structures:: fx:: FxHashMap ;
19+ use arena:: DroplessArena ;
1920use serialize:: { Decodable , Decoder , Encodable , Encoder } ;
2021use std:: fmt;
22+ use std:: str;
2123use std:: cmp:: { PartialEq , Ordering , PartialOrd , Ord } ;
2224use std:: hash:: { Hash , Hasher } ;
2325
@@ -198,22 +200,35 @@ impl<T: ::std::ops::Deref<Target=str>> PartialEq<T> for Symbol {
198200 }
199201}
200202
201- # [ derive ( Default ) ]
203+ // The &'static strs in this type actually point into the arena
202204pub struct Interner {
203- names : FxHashMap < Box < str > , Symbol > ,
204- strings : Vec < Box < str > > ,
205+ arena : DroplessArena ,
206+ names : FxHashMap < & ' static str , Symbol > ,
207+ strings : Vec < & ' static str > ,
205208 gensyms : Vec < Symbol > ,
206209}
207210
208211impl Interner {
209212 pub fn new ( ) -> Self {
210- Interner :: default ( )
213+ Interner {
214+ arena : DroplessArena :: new ( ) ,
215+ names : Default :: default ( ) ,
216+ strings : Default :: default ( ) ,
217+ gensyms : Default :: default ( ) ,
218+ }
211219 }
212220
213221 fn prefill ( init : & [ & str ] ) -> Self {
214222 let mut this = Interner :: new ( ) ;
215223 for & string in init {
216- this. intern ( string) ;
224+ if string == "" {
225+ // We can't allocate empty strings in the arena, so handle this here
226+ let name = Symbol ( this. strings . len ( ) as u32 ) ;
227+ this. names . insert ( "" , name) ;
228+ this. strings . push ( "" ) ;
229+ } else {
230+ this. intern ( string) ;
231+ }
217232 }
218233 this
219234 }
@@ -224,8 +239,17 @@ impl Interner {
224239 }
225240
226241 let name = Symbol ( self . strings . len ( ) as u32 ) ;
227- let string = string. to_string ( ) . into_boxed_str ( ) ;
228- self . strings . push ( string. clone ( ) ) ;
242+
243+ // from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
244+ let string: & str = unsafe {
245+ str:: from_utf8_unchecked ( self . arena . alloc_slice ( string. as_bytes ( ) ) )
246+ } ;
247+ // It is safe to extend the arena allocation to 'static because we only access
248+ // these while the arena is still alive
249+ let string: & ' static str = unsafe {
250+ & * ( string as * const str )
251+ } ;
252+ self . strings . push ( string) ;
229253 self . names . insert ( string, name) ;
230254 name
231255 }
@@ -254,7 +278,7 @@ impl Interner {
254278
255279 pub fn get ( & self , symbol : Symbol ) -> & str {
256280 match self . strings . get ( symbol. 0 as usize ) {
257- Some ( ref string) => string,
281+ Some ( string) => string,
258282 None => self . get ( self . gensyms [ ( !0 - symbol. 0 ) as usize ] ) ,
259283 }
260284 }
0 commit comments