Skip to content

Commit 4961d72

Browse files
committed
Auto merge of #41507 - arielb1:symbol-cache, r=nikomatsakis
cache symbol names in ty::maps this fixes a performance regression introduced in commit 39a58c3. r? @nikomatsakis
2 parents 79b05fe + 07b16cb commit 4961d72

16 files changed

+220
-347
lines changed

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub enum DepNode<D: Clone + Debug> {
9999
TypeckTables(D),
100100
UsedTraitImports(D),
101101
ConstEval(D),
102+
SymbolName(D),
102103

103104
// The set of impls for a given trait. Ultimately, it would be
104105
// nice to get more fine-grained here (e.g., to include a
@@ -236,6 +237,7 @@ impl<D: Clone + Debug> DepNode<D> {
236237
TypeckTables(ref d) => op(d).map(TypeckTables),
237238
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
238239
ConstEval(ref d) => op(d).map(ConstEval),
240+
SymbolName(ref d) => op(d).map(SymbolName),
239241
TraitImpls(ref d) => op(d).map(TraitImpls),
240242
TraitItems(ref d) => op(d).map(TraitItems),
241243
ReprHints(ref d) => op(d).map(ReprHints),

src/librustc/ty/maps.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::cell::{RefCell, RefMut};
2424
use std::ops::Deref;
2525
use std::rc::Rc;
2626
use syntax_pos::{Span, DUMMY_SP};
27+
use syntax::symbol::Symbol;
2728

2829
trait Key {
2930
fn map_crate(&self) -> CrateNum;
@@ -40,6 +41,16 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> {
4041
}
4142
}
4243

44+
impl<'tcx> Key for ty::Instance<'tcx> {
45+
fn map_crate(&self) -> CrateNum {
46+
LOCAL_CRATE
47+
}
48+
49+
fn default_span(&self, tcx: TyCtxt) -> Span {
50+
tcx.def_span(self.def_id())
51+
}
52+
}
53+
4354
impl Key for CrateNum {
4455
fn map_crate(&self) -> CrateNum {
4556
*self
@@ -108,13 +119,18 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
108119
}
109120
}
110121

111-
112122
impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
113123
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
114124
Self::empty()
115125
}
116126
}
117127

128+
impl<'tcx> Value<'tcx> for ty::SymbolName {
129+
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
130+
ty::SymbolName { name: Symbol::intern("<error>").as_str() }
131+
}
132+
}
133+
118134
pub struct CycleError<'a, 'tcx: 'a> {
119135
span: Span,
120136
cycle: RefMut<'a, [(Span, Query<'tcx>)]>,
@@ -242,6 +258,12 @@ impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
242258
}
243259
}
244260

261+
impl<'tcx> QueryDescription for queries::symbol_name<'tcx> {
262+
fn describe(_tcx: TyCtxt, instance: ty::Instance<'tcx>) -> String {
263+
format!("computing the symbol for `{}`", instance)
264+
}
265+
}
266+
245267
macro_rules! define_maps {
246268
(<$tcx:tt>
247269
$($(#[$attr:meta])*
@@ -513,7 +535,10 @@ define_maps! { <'tcx>
513535

514536
pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
515537

516-
pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
538+
pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
539+
540+
pub def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
541+
pub symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName
517542
}
518543

519544
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -532,6 +557,12 @@ fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
532557
instance.dep_node()
533558
}
534559

560+
fn symbol_name_dep_node(instance: ty::Instance) -> DepNode<DefId> {
561+
// symbol_name uses the substs only to traverse them to find the
562+
// hash, and that does not create any new dep-nodes.
563+
DepNode::SymbolName(instance.def.def_id())
564+
}
565+
535566
fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
536567
DepNode::TypeckBodiesKrate
537568
}

src/librustc/ty/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use serialize::{self, Encodable, Encoder};
3838
use std::cell::{Cell, RefCell, Ref};
3939
use std::collections::BTreeMap;
4040
use std::cmp;
41+
use std::fmt;
4142
use std::hash::{Hash, Hasher};
4243
use std::iter::FromIterator;
4344
use std::ops::Deref;
@@ -2745,3 +2746,22 @@ impl<'tcx> DtorckConstraint<'tcx> {
27452746
self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
27462747
}
27472748
}
2749+
2750+
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
2751+
pub struct SymbolName {
2752+
// FIXME: we don't rely on interning or equality here - better have
2753+
// this be a `&'tcx str`.
2754+
pub name: InternedString
2755+
}
2756+
2757+
impl Deref for SymbolName {
2758+
type Target = str;
2759+
2760+
fn deref(&self) -> &str { &self.name }
2761+
}
2762+
2763+
impl fmt::Display for SymbolName {
2764+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2765+
fmt::Display::fmt(&self.name, fmt)
2766+
}
2767+
}

src/librustc_driver/driver.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ pub fn compile_input(sess: &Session,
225225
sess.code_stats.borrow().print_type_sizes();
226226
}
227227

228-
if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); }
229-
230228
let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
231229

232230
controller_entry_point!(after_llvm,
@@ -895,13 +893,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
895893
mir::provide(&mut local_providers);
896894
reachable::provide(&mut local_providers);
897895
rustc_privacy::provide(&mut local_providers);
896+
trans::provide(&mut local_providers);
898897
typeck::provide(&mut local_providers);
899898
ty::provide(&mut local_providers);
900899
reachable::provide(&mut local_providers);
901900
rustc_const_eval::provide(&mut local_providers);
902901

903902
let mut extern_providers = ty::maps::Providers::default();
904903
cstore::provide(&mut extern_providers);
904+
trans::provide(&mut extern_providers);
905905
ty::provide_extern(&mut extern_providers);
906906
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
907907
rustc_const_eval::provide(&mut extern_providers);

src/librustc_trans/back/symbol_export.rs

+8-33
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,11 @@
1010

1111
use context::SharedCrateContext;
1212
use monomorphize::Instance;
13-
use symbol_map::SymbolMap;
14-
use back::symbol_names::symbol_name;
1513
use util::nodemap::FxHashMap;
1614
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
1715
use rustc::session::config;
1816
use rustc::ty::TyCtxt;
1917
use syntax::attr;
20-
use trans_item::TransItem;
2118

2219
/// The SymbolExportLevel of a symbols specifies from which kinds of crates
2320
/// the symbol will be exported. `C` symbols will be exported from any
@@ -36,27 +33,24 @@ pub struct ExportedSymbols {
3633
}
3734

3835
impl ExportedSymbols {
39-
4036
pub fn empty() -> ExportedSymbols {
4137
ExportedSymbols {
4238
exports: FxHashMap(),
4339
}
4440
}
4541

46-
pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
47-
symbol_map: &SymbolMap<'tcx>)
48-
-> ExportedSymbols {
42+
pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols {
4943
let mut local_crate: Vec<_> = scx
5044
.exported_symbols()
5145
.iter()
5246
.map(|&node_id| {
5347
scx.tcx().hir.local_def_id(node_id)
5448
})
5549
.map(|def_id| {
56-
let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map);
50+
let name = scx.tcx().symbol_name(Instance::mono(scx.tcx(), def_id));
5751
let export_level = export_level(scx, def_id);
5852
debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
59-
(name, export_level)
53+
(str::to_owned(&name), export_level)
6054
})
6155
.collect();
6256

@@ -108,7 +102,7 @@ impl ExportedSymbols {
108102
.exported_symbols(cnum)
109103
.iter()
110104
.map(|&def_id| {
111-
let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx());
105+
let name = scx.tcx().symbol_name(Instance::mono(scx.tcx(), def_id));
112106
let export_level = if special_runtime_crate {
113107
// We can probably do better here by just ensuring that
114108
// it has hidden visibility rather than public
@@ -117,9 +111,9 @@ impl ExportedSymbols {
117111
//
118112
// In general though we won't link right if these
119113
// symbols are stripped, and LTO currently strips them.
120-
if name == "rust_eh_personality" ||
121-
name == "rust_eh_register_frames" ||
122-
name == "rust_eh_unregister_frames" {
114+
if &*name == "rust_eh_personality" ||
115+
&*name == "rust_eh_register_frames" ||
116+
&*name == "rust_eh_unregister_frames" {
123117
SymbolExportLevel::C
124118
} else {
125119
SymbolExportLevel::Rust
@@ -128,7 +122,7 @@ impl ExportedSymbols {
128122
export_level(scx, def_id)
129123
};
130124
debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
131-
(name, export_level)
125+
(str::to_owned(&name), export_level)
132126
})
133127
.collect();
134128

@@ -213,22 +207,3 @@ pub fn is_below_threshold(level: SymbolExportLevel,
213207
level == SymbolExportLevel::C
214208
}
215209
}
216-
217-
fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
218-
def_id: DefId,
219-
symbol_map: &SymbolMap<'tcx>)
220-
-> String {
221-
// Just try to look things up in the symbol map. If nothing's there, we
222-
// recompute.
223-
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
224-
if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
225-
return sym.to_owned();
226-
}
227-
}
228-
229-
let instance = Instance::mono(tcx, def_id);
230-
231-
symbol_map.get(TransItem::Fn(instance))
232-
.map(str::to_owned)
233-
.unwrap_or_else(|| symbol_name(instance, tcx))
234-
}

src/librustc_trans/back/symbol_names.rs

+49-14
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,24 @@ use rustc::hir::map as hir_map;
105105
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
106106
use rustc::ty::fold::TypeVisitor;
107107
use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
108+
use rustc::ty::maps::Providers;
108109
use rustc::ty::subst::Substs;
109110
use rustc::hir::map::definitions::DefPathData;
110111
use rustc::util::common::record_time;
111112

112113
use syntax::attr;
114+
use syntax_pos::symbol::Symbol;
113115

114116
use std::fmt::Write;
115117

118+
pub fn provide(providers: &mut Providers) {
119+
*providers = Providers {
120+
def_symbol_name,
121+
symbol_name,
122+
..*providers
123+
};
124+
}
125+
116126
fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
117127

118128
// the DefId of the item this name is for
@@ -127,7 +137,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
127137
// values for generic type parameters,
128138
// if any.
129139
substs: Option<&'tcx Substs<'tcx>>)
130-
-> String {
140+
-> u64 {
131141
debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
132142

133143
let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
@@ -162,11 +172,28 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
162172
});
163173

164174
// 64 bits should be enough to avoid collisions.
165-
format!("h{:016x}", hasher.finish())
175+
hasher.finish()
176+
}
177+
178+
fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
179+
-> ty::SymbolName
180+
{
181+
let mut buffer = SymbolPathBuffer::new();
182+
item_path::with_forced_absolute_paths(|| {
183+
tcx.push_item_path(&mut buffer, def_id);
184+
});
185+
buffer.into_interned()
166186
}
167187

168-
pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
169-
tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
188+
fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
189+
-> ty::SymbolName
190+
{
191+
ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() }
192+
}
193+
194+
fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
195+
-> String
196+
{
170197
let def_id = instance.def_id();
171198
let substs = instance.substs;
172199

@@ -253,11 +280,7 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
253280

254281
let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs));
255282

256-
let mut buffer = SymbolPathBuffer::new();
257-
item_path::with_forced_absolute_paths(|| {
258-
tcx.push_item_path(&mut buffer, def_id);
259-
});
260-
buffer.finish(&hash)
283+
SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
261284
}
262285

263286
// Follow C++ namespace-mangling style, see
@@ -288,10 +311,22 @@ impl SymbolPathBuffer {
288311
result
289312
}
290313

291-
fn finish(mut self, hash: &str) -> String {
292-
// end name-sequence
293-
self.push(hash);
294-
self.result.push('E');
314+
fn from_interned(symbol: ty::SymbolName) -> Self {
315+
let mut result = SymbolPathBuffer {
316+
result: String::with_capacity(64),
317+
temp_buf: String::with_capacity(16)
318+
};
319+
result.result.push_str(&symbol.name);
320+
result
321+
}
322+
323+
fn into_interned(self) -> ty::SymbolName {
324+
ty::SymbolName { name: Symbol::intern(&self.result).as_str() }
325+
}
326+
327+
fn finish(mut self, hash: u64) -> String {
328+
// E = end name-sequence
329+
let _ = write!(self.result, "17h{:016x}E", hash);
295330
self.result
296331
}
297332
}
@@ -320,7 +355,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
320355
let hash = get_symbol_hash(tcx, None, t, None);
321356
let mut buffer = SymbolPathBuffer::new();
322357
buffer.push(prefix);
323-
buffer.finish(&hash)
358+
buffer.finish(hash)
324359
}
325360

326361
// Name sanitation. LLVM will happily accept identifiers with weird names, but

0 commit comments

Comments
 (0)