Skip to content

Commit ca32340

Browse files
committed
Allocate Symbol strings from an arena
1 parent 57dc984 commit ca32340

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

Diff for: src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/libsyntax_pos/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ crate-type = ["dylib"]
1111
[dependencies]
1212
serialize = { path = "../libserialize" }
1313
rustc_data_structures = { path = "../librustc_data_structures" }
14+
arena = { path = "../libarena" }
1415
scoped-tls = { version = "0.1.1", features = ["nightly"] }
1516
unicode-width = "0.1.4"

Diff for: src/libsyntax_pos/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use std::path::PathBuf;
3535
use rustc_data_structures::stable_hasher::StableHasher;
3636
use rustc_data_structures::sync::{Lrc, Lock};
3737

38+
extern crate arena;
3839
extern crate rustc_data_structures;
3940

4041
#[macro_use]

Diff for: src/libsyntax_pos/symbol.rs

+32-8
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ use hygiene::SyntaxContext;
1616
use {Span, DUMMY_SP, GLOBALS};
1717

1818
use rustc_data_structures::fx::FxHashMap;
19+
use arena::DroplessArena;
1920
use serialize::{Decodable, Decoder, Encodable, Encoder};
2021
use std::fmt;
22+
use std::str;
2123
use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
2224
use 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
202204
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>,
205208
gensyms: Vec<Symbol>,
206209
}
207210

208211
impl 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

Comments
 (0)