Skip to content

Commit 81af6fb

Browse files
Ariel Ben-Yehudaarielb1
Ariel Ben-Yehuda
authored andcommitted
allocate less strings in symbol_names
this improves trans performance by *another* 10%.
1 parent 266d36f commit 81af6fb

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
@@ -110,7 +110,8 @@ use rustc::hir::map::definitions::DefPathData;
110110
use rustc::util::common::record_time;
111111

112112
use syntax::attr;
113-
use syntax::symbol::{Symbol, InternedString};
113+
114+
use std::fmt::Write;
114115

115116
fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
116117

@@ -252,19 +253,47 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
252253

253254
let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs));
254255

255-
let mut buffer = SymbolPathBuffer {
256-
names: Vec::new()
257-
};
258-
256+
let mut buffer = SymbolPathBuffer::new();
259257
item_path::with_forced_absolute_paths(|| {
260258
tcx.push_item_path(&mut buffer, def_id);
261259
});
262-
263-
mangle(buffer.names.into_iter(), &hash)
260+
buffer.finish(&hash)
264261
}
265262

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

270299
impl ItemPathBuffer for SymbolPathBuffer {
@@ -274,7 +303,13 @@ impl ItemPathBuffer for SymbolPathBuffer {
274303
}
275304

276305
fn push(&mut self, text: &str) {
277-
self.names.push(Symbol::intern(text).as_str());
306+
self.temp_buf.clear();
307+
let need_underscore = sanitize(&mut self.temp_buf, text);
308+
let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
309+
if need_underscore {
310+
self.result.push('_');
311+
}
312+
self.result.push_str(&self.temp_buf);
278313
}
279314
}
280315

@@ -283,15 +318,17 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
283318
prefix: &str)
284319
-> String {
285320
let hash = get_symbol_hash(tcx, None, t, None);
286-
let path = [Symbol::intern(prefix).as_str()];
287-
mangle(path.iter().cloned(), &hash)
321+
let mut buffer = SymbolPathBuffer::new();
322+
buffer.push(prefix);
323+
buffer.finish(&hash)
288324
}
289325

290326
// Name sanitation. LLVM will happily accept identifiers with weird names, but
291327
// gas doesn't!
292328
// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
293-
pub fn sanitize(s: &str) -> String {
294-
let mut result = String::new();
329+
//
330+
// returns true if an underscore must be added at the start
331+
pub fn sanitize(result: &mut String, s: &str) -> bool {
295332
for c in s.chars() {
296333
match c {
297334
// Escape these with $ sequences
@@ -328,44 +365,7 @@ pub fn sanitize(s: &str) -> String {
328365
}
329366

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

0 commit comments

Comments
 (0)