Skip to content

Commit ecfab94

Browse files
author
Ariel Ben-Yehuda
committed
allocate less strings in symbol_names
this improves trans performance by *another* 10%.
1 parent b69084c commit ecfab94

File tree

1 file changed

+52
-52
lines changed

1 file changed

+52
-52
lines changed

src/librustc_trans/back/symbol_names.rs

+52-52
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ use rustc::hir::map::definitions::DefPathData;
111111
use rustc::util::common::record_time;
112112

113113
use syntax::attr;
114-
use syntax::symbol::{Symbol, InternedString};
114+
115+
use std::fmt::Write;
115116

116117
fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
117118

@@ -255,19 +256,47 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
255256

256257
let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs));
257258

258-
let mut buffer = SymbolPathBuffer {
259-
names: Vec::new()
260-
};
261-
259+
let mut buffer = SymbolPathBuffer::new();
262260
item_path::with_forced_absolute_paths(|| {
263261
scx.tcx().push_item_path(&mut buffer, def_id);
264262
});
265-
266-
mangle(buffer.names.into_iter(), &hash)
263+
buffer.finish(&hash)
267264
}
268265

266+
// Follow C++ namespace-mangling style, see
267+
// http://en.wikipedia.org/wiki/Name_mangling for more info.
268+
//
269+
// It turns out that on macOS you can actually have arbitrary symbols in
270+
// function names (at least when given to LLVM), but this is not possible
271+
// when using unix's linker. Perhaps one day when we just use a linker from LLVM
272+
// we won't need to do this name mangling. The problem with name mangling is
273+
// that it seriously limits the available characters. For example we can't
274+
// have things like &T in symbol names when one would theoretically
275+
// want them for things like impls of traits on that type.
276+
//
277+
// To be able to work on all platforms and get *some* reasonable output, we
278+
// use C++ name-mangling.
269279
struct SymbolPathBuffer {
270-
names: Vec<InternedString>,
280+
result: String,
281+
temp_buf: String
282+
}
283+
284+
impl SymbolPathBuffer {
285+
fn new() -> Self {
286+
let mut result = SymbolPathBuffer {
287+
result: String::with_capacity(64),
288+
temp_buf: String::with_capacity(16)
289+
};
290+
result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
291+
result
292+
}
293+
294+
fn finish(mut self, hash: &str) -> String {
295+
// end name-sequence
296+
self.push(hash);
297+
self.result.push('E');
298+
self.result
299+
}
271300
}
272301

273302
impl ItemPathBuffer for SymbolPathBuffer {
@@ -277,7 +306,13 @@ impl ItemPathBuffer for SymbolPathBuffer {
277306
}
278307

279308
fn push(&mut self, text: &str) {
280-
self.names.push(Symbol::intern(text).as_str());
309+
self.temp_buf.clear();
310+
let need_underscore = sanitize(&mut self.temp_buf, text);
311+
let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
312+
if need_underscore {
313+
self.result.push('_');
314+
}
315+
self.result.push_str(&self.temp_buf);
281316
}
282317
}
283318

@@ -286,15 +321,17 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
286321
prefix: &str)
287322
-> String {
288323
let hash = get_symbol_hash(scx, None, t, None);
289-
let path = [Symbol::intern(prefix).as_str()];
290-
mangle(path.iter().cloned(), &hash)
324+
let mut buffer = SymbolPathBuffer::new();
325+
buffer.push(prefix);
326+
buffer.finish(&hash)
291327
}
292328

293329
// Name sanitation. LLVM will happily accept identifiers with weird names, but
294330
// gas doesn't!
295331
// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
296-
pub fn sanitize(s: &str) -> String {
297-
let mut result = String::new();
332+
//
333+
// returns true if an underscore must be added at the start
334+
pub fn sanitize(result: &mut String, s: &str) -> bool {
298335
for c in s.chars() {
299336
match c {
300337
// Escape these with $ sequences
@@ -331,44 +368,7 @@ pub fn sanitize(s: &str) -> String {
331368
}
332369

333370
// Underscore-qualify anything that didn't start as an ident.
334-
if !result.is_empty() &&
371+
!result.is_empty() &&
335372
result.as_bytes()[0] != '_' as u8 &&
336-
! (result.as_bytes()[0] as char).is_xid_start() {
337-
return format!("_{}", result);
338-
}
339-
340-
return result;
341-
}
342-
343-
fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
344-
// Follow C++ namespace-mangling style, see
345-
// http://en.wikipedia.org/wiki/Name_mangling for more info.
346-
//
347-
// It turns out that on macOS you can actually have arbitrary symbols in
348-
// function names (at least when given to LLVM), but this is not possible
349-
// when using unix's linker. Perhaps one day when we just use a linker from LLVM
350-
// we won't need to do this name mangling. The problem with name mangling is
351-
// that it seriously limits the available characters. For example we can't
352-
// have things like &T in symbol names when one would theoretically
353-
// want them for things like impls of traits on that type.
354-
//
355-
// To be able to work on all platforms and get *some* reasonable output, we
356-
// use C++ name-mangling.
357-
358-
let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
359-
360-
fn push(n: &mut String, s: &str) {
361-
let sani = sanitize(s);
362-
n.push_str(&format!("{}{}", sani.len(), sani));
363-
}
364-
365-
// First, connect each component with <len, name> pairs.
366-
for data in path {
367-
push(&mut n, &data);
368-
}
369-
370-
push(&mut n, hash);
371-
372-
n.push('E'); // End name-sequence.
373-
n
373+
! (result.as_bytes()[0] as char).is_xid_start()
374374
}

0 commit comments

Comments
 (0)