Allocate Symbol strings from an arena · rust-lang/rust@ca32340 (original) (raw)

`@@ -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 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, Symbol>,

`

204

``

`-

strings: Vec<Box>,

`

``

205

`+

arena: DroplessArena,

`

``

206

`+

names: FxHashMap<&'static str, Symbol>,

`

``

207

`+

strings: Vec<&'static str>,

`

205

208

`gensyms: Vec,

`

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

`}

`