Skip to content

Commit c771100

Browse files
arielb1Ariel Ben-Yehuda
authored and
Ariel Ben-Yehuda
committed
Make caching in stability work. This improves stability check performance
by 90%.
1 parent 014bf0d commit c771100

File tree

10 files changed

+150
-97
lines changed

10 files changed

+150
-97
lines changed

src/librustc/metadata/csearch.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -380,15 +380,20 @@ pub fn is_const_fn(cstore: &cstore::CStore, did: ast::DefId) -> bool {
380380
decoder::is_const_fn(&*cdata, did.node)
381381
}
382382

383+
pub fn is_impl(cstore: &cstore::CStore, did: ast::DefId) -> bool {
384+
let cdata = cstore.get_crate_data(did.krate);
385+
decoder::is_impl(&*cdata, did.node)
386+
}
387+
383388
pub fn get_stability(cstore: &cstore::CStore,
384389
def: ast::DefId)
385390
-> Option<attr::Stability> {
386391
let cdata = cstore.get_crate_data(def.krate);
387392
decoder::get_stability(&*cdata, def.node)
388393
}
389394

390-
pub fn is_staged_api(cstore: &cstore::CStore, def: ast::DefId) -> bool {
391-
let cdata = cstore.get_crate_data(def.krate);
395+
pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool {
396+
let cdata = cstore.get_crate_data(krate);
392397
let attrs = decoder::get_crate_attributes(cdata.data());
393398
for attr in &attrs {
394399
if &attr.name()[..] == "staged_api" {

src/librustc/metadata/decoder.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,14 @@ pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
15331533
}
15341534
}
15351535

1536+
pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool {
1537+
let item_doc = lookup_item(id, cdata.data());
1538+
match item_family(item_doc) {
1539+
Impl => true,
1540+
_ => false,
1541+
}
1542+
}
1543+
15361544
fn doc_generics<'tcx>(base_doc: rbml::Doc,
15371545
tcx: &ty::ctxt<'tcx>,
15381546
cdata: Cmd,

src/librustc/metadata/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ fn encode_extension_implementations(ecx: &EncodeContext,
999999
});
10001000
}
10011001

1002-
fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<attr::Stability>) {
1002+
fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
10031003
stab_opt.map(|stab| {
10041004
rbml_w.start_tag(tag_items_data_item_stability);
10051005
stab.encode(rbml_w).unwrap();

src/librustc/middle/stability.rs

+69-61
Original file line numberDiff line numberDiff line change
@@ -23,46 +23,47 @@ use syntax::{attr, visit};
2323
use syntax::ast;
2424
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
2525
use syntax::ast::{Item, Generics, StructField};
26-
use syntax::ast_util::is_local;
26+
use syntax::ast_util::{is_local, local_def};
2727
use syntax::attr::{Stability, AttrMetaMethods};
2828
use syntax::visit::{FnKind, Visitor};
2929
use syntax::feature_gate::emit_feature_err;
30-
use util::nodemap::{NodeMap, DefIdMap, FnvHashSet, FnvHashMap};
30+
use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
3131
use util::ppaux::Repr;
3232

3333
use std::mem::replace;
3434

3535
/// A stability index, giving the stability level for items and methods.
36-
pub struct Index {
37-
// Indicates whether this crate has #![feature(staged_api)]
38-
staged_api: bool,
39-
// stability for crate-local items; unmarked stability == no entry
40-
local: NodeMap<Stability>,
41-
// cache for extern-crate items; unmarked stability == entry with None
42-
extern_cache: DefIdMap<Option<Stability>>
36+
pub struct Index<'tcx> {
37+
/// This is mostly a cache, except the stabilities of local items
38+
/// are filled by the annotator.
39+
map: DefIdMap<Option<&'tcx Stability>>,
40+
41+
/// Maps for each crate whether it is part of the staged API.
42+
staged_api: FnvHashMap<ast::CrateNum, bool>
4343
}
4444

4545
// A private tree-walker for producing an Index.
46-
struct Annotator<'a> {
47-
sess: &'a Session,
48-
index: &'a mut Index,
49-
parent: Option<Stability>,
46+
struct Annotator<'a, 'tcx: 'a> {
47+
tcx: &'a ty::ctxt<'tcx>,
48+
index: &'a mut Index<'tcx>,
49+
parent: Option<&'tcx Stability>,
5050
export_map: &'a PublicItems,
5151
}
5252

53-
impl<'a> Annotator<'a> {
53+
impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
5454
// Determine the stability for a node based on its attributes and inherited
5555
// stability. The stability is recorded in the index and used as the parent.
5656
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
5757
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
5858
F: FnOnce(&mut Annotator),
5959
{
60-
if self.index.staged_api {
60+
if self.index.staged_api[&ast::LOCAL_CRATE] {
6161
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
62-
match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
62+
match attr::find_stability(self.tcx.sess.diagnostic(), attrs, item_sp) {
6363
Some(stab) => {
6464
debug!("annotate: found {:?}", stab);
65-
self.index.local.insert(id, stab.clone());
65+
let stab = self.tcx.intern_stability(stab);
66+
self.index.map.insert(local_def(id), Some(stab));
6667

6768
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
6869
if stab.level != attr::Stable {
@@ -77,13 +78,14 @@ impl<'a> Annotator<'a> {
7778
debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
7879
use_parent, self.parent);
7980
if use_parent {
80-
if let Some(stab) = self.parent.clone() {
81-
self.index.local.insert(id, stab);
82-
} else if self.index.staged_api && required
81+
if let Some(stab) = self.parent {
82+
self.index.map.insert(local_def(id), Some(stab));
83+
} else if self.index.staged_api[&ast::LOCAL_CRATE] && required
8384
&& self.export_map.contains(&id)
84-
&& !self.sess.opts.test {
85-
self.sess.span_err(item_sp,
86-
"This node does not have a stability attribute");
85+
&& !self.tcx.sess.opts.test {
86+
self.tcx.sess.span_err(item_sp,
87+
"This node does not \
88+
have a stability attribute");
8789
}
8890
}
8991
f(self);
@@ -95,7 +97,7 @@ impl<'a> Annotator<'a> {
9597
let tag = attr.name();
9698
if tag == "unstable" || tag == "stable" || tag == "deprecated" {
9799
attr::mark_used(attr);
98-
self.sess.span_err(attr.span(),
100+
self.tcx.sess.span_err(attr.span(),
99101
"stability attributes may not be used outside \
100102
of the standard library");
101103
}
@@ -105,7 +107,7 @@ impl<'a> Annotator<'a> {
105107
}
106108
}
107109

108-
impl<'a, 'v> Visitor<'v> for Annotator<'a> {
110+
impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
109111
fn visit_item(&mut self, i: &Item) {
110112
// FIXME (#18969): the following is a hack around the fact
111113
// that we cannot currently annotate the stability of
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
168170
}
169171
}
170172

171-
impl Index {
173+
impl<'tcx> Index<'tcx> {
172174
/// Construct the stability index for a crate being compiled.
173-
pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
175+
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, export_map: &PublicItems) {
174176
let mut annotator = Annotator {
175-
sess: sess,
177+
tcx: tcx,
176178
index: self,
177179
parent: None,
178180
export_map: export_map,
@@ -182,22 +184,23 @@ impl Index {
182184
}
183185

184186
pub fn new(krate: &Crate) -> Index {
185-
let mut staged_api = false;
187+
let mut is_staged_api = false;
186188
for attr in &krate.attrs {
187189
if &attr.name()[..] == "staged_api" {
188190
match attr.node.value.node {
189191
ast::MetaWord(_) => {
190192
attr::mark_used(attr);
191-
staged_api = true;
193+
is_staged_api = true;
192194
}
193195
_ => (/*pass*/)
194196
}
195197
}
196198
}
199+
let mut staged_api = FnvHashMap();
200+
staged_api.insert(ast::LOCAL_CRATE, is_staged_api);
197201
Index {
198202
staged_api: staged_api,
199-
local: NodeMap(),
200-
extern_cache: DefIdMap()
203+
map: DefIdMap(),
201204
}
202205
}
203206
}
@@ -232,13 +235,13 @@ struct Checker<'a, 'tcx: 'a> {
232235
}
233236

234237
impl<'a, 'tcx> Checker<'a, 'tcx> {
235-
fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<Stability>) {
238+
fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<&Stability>) {
236239
// Only the cross-crate scenario matters when checking unstable APIs
237240
let cross_crate = !is_local(id);
238241
if !cross_crate { return }
239242

240243
match *stab {
241-
Some(Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
244+
Some(&Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
242245
self.used_features.insert(feature.clone(), attr::Unstable);
243246

244247
if !self.active_features.contains(feature) {
@@ -252,7 +255,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
252255
&feature, span, &msg);
253256
}
254257
}
255-
Some(Stability { level, ref feature, .. }) => {
258+
Some(&Stability { level, ref feature, .. }) => {
256259
self.used_features.insert(feature.clone(), level);
257260

258261
// Stable APIs are always ok to call and deprecated APIs are
@@ -312,7 +315,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
312315

313316
/// Helper for discovering nodes to check for stability
314317
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
315-
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
318+
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
316319
match item.node {
317320
ast::ItemExternCrate(_) => {
318321
// compiler-generated `extern crate` items have a dummy span.
@@ -349,7 +352,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
349352

350353
/// Helper for discovering nodes to check for stability
351354
pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
352-
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
355+
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
353356
let span;
354357
let id = match e.node {
355358
ast::ExprMethodCall(i, _, _) => {
@@ -458,7 +461,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
458461
}
459462

460463
pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
461-
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
464+
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
462465
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
463466
Some(def::DefPrimTy(..)) => {}
464467
Some(def) => {
@@ -470,7 +473,7 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
470473
}
471474

472475
pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
473-
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
476+
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
474477
debug!("check_pat(pat = {:?})", pat);
475478
if is_internal(tcx, pat.span) { return; }
476479

@@ -511,7 +514,7 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
511514
}
512515

513516
fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
514-
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
517+
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
515518
if !is_staged_api(tcx, id) { return }
516519
if is_internal(tcx, span) { return }
517520
let ref stability = lookup(tcx, id);
@@ -528,20 +531,27 @@ fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
528531
if trait_method_id != id => {
529532
is_staged_api(tcx, trait_method_id)
530533
}
531-
_ if is_local(id) => {
532-
tcx.stability.borrow().staged_api
533-
}
534534
_ => {
535-
csearch::is_staged_api(&tcx.sess.cstore, id)
535+
*tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
536+
|| csearch::is_staged_api(&tcx.sess.cstore, id.krate))
536537
}
537538
}
538539
}
539540

540541
/// Lookup the stability for a node, loading external crate
541542
/// metadata as necessary.
542-
pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
543-
debug!("lookup(id={})",
544-
id.repr(tcx));
543+
pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
544+
if let Some(st) = tcx.stability.borrow().map.get(&id) {
545+
return *st;
546+
}
547+
548+
let st = lookup_uncached(tcx, id);
549+
tcx.stability.borrow_mut().map.insert(id, st);
550+
st
551+
}
552+
553+
fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
554+
debug!("lookup(id={})", id.repr(tcx));
545555

546556
// is this definition the implementation of a trait method?
547557
match ty::trait_item_of_item(tcx, id) {
@@ -553,25 +563,23 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
553563
}
554564

555565
let item_stab = if is_local(id) {
556-
tcx.stability.borrow().local.get(&id.node).cloned()
566+
None // The stability cache is filled partially lazily
557567
} else {
558-
let stab = csearch::get_stability(&tcx.sess.cstore, id);
559-
let mut index = tcx.stability.borrow_mut();
560-
(*index).extern_cache.insert(id, stab.clone());
561-
stab
568+
csearch::get_stability(&tcx.sess.cstore, id).map(|st| tcx.intern_stability(st))
562569
};
563570

564571
item_stab.or_else(|| {
565-
if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
566-
// FIXME (#18969): for the time being, simply use the
567-
// stability of the trait to determine the stability of any
568-
// unmarked impls for it. See FIXME above for more details.
569-
570-
debug!("lookup: trait_id={:?}", trait_id);
571-
lookup(tcx, trait_id)
572-
} else {
573-
None
572+
if ty::is_impl(tcx, id) {
573+
if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
574+
// FIXME (#18969): for the time being, simply use the
575+
// stability of the trait to determine the stability of any
576+
// unmarked impls for it. See FIXME above for more details.
577+
578+
debug!("lookup: trait_id={:?}", trait_id);
579+
return lookup(tcx, trait_id);
580+
}
574581
}
582+
None
575583
})
576584
}
577585

0 commit comments

Comments
 (0)