@@ -16,8 +16,10 @@ use hygiene::SyntaxContext;
16
16
use { Span , DUMMY_SP , GLOBALS } ;
17
17
18
18
use rustc_data_structures:: fx:: FxHashMap ;
19
+ use arena:: DroplessArena ;
19
20
use serialize:: { Decodable , Decoder , Encodable , Encoder } ;
20
21
use std:: fmt;
22
+ use std:: str;
21
23
use std:: cmp:: { PartialEq , Ordering , PartialOrd , Ord } ;
22
24
use std:: hash:: { Hash , Hasher } ;
23
25
@@ -198,22 +200,35 @@ impl<T: ::std::ops::Deref<Target=str>> PartialEq<T> for Symbol {
198
200
}
199
201
}
200
202
201
- # [ derive ( Default ) ]
203
+ // The &'static strs in this type actually point into the arena
202
204
pub 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 > ,
205
208
gensyms : Vec < Symbol > ,
206
209
}
207
210
208
211
impl Interner {
209
212
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
+ }
211
219
}
212
220
213
221
fn prefill ( init : & [ & str ] ) -> Self {
214
222
let mut this = Interner :: new ( ) ;
215
223
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
+ }
217
232
}
218
233
this
219
234
}
@@ -224,8 +239,17 @@ impl Interner {
224
239
}
225
240
226
241
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) ;
229
253
self . names . insert ( string, name) ;
230
254
name
231
255
}
@@ -254,7 +278,7 @@ impl Interner {
254
278
255
279
pub fn get ( & self , symbol : Symbol ) -> & str {
256
280
match self . strings . get ( symbol. 0 as usize ) {
257
- Some ( ref string) => string,
281
+ Some ( string) => string,
258
282
None => self . get ( self . gensyms [ ( !0 - symbol. 0 ) as usize ] ) ,
259
283
}
260
284
}
0 commit comments