Skip to content

Commit 0248c6f

Browse files
committed
Auto merge of #81398 - bugadani:rustdoc-perf, r=GuillaumeGomez
rustdoc tweaking * Reuse memory * simplify `next_def_id`, avoid multiple hashing and unnecessary lookups * remove `all_fake_def_ids`, use the global map instead (probably not a good step toward parallelization, though...) * convert `add_deref_target` to iterative implementation * use `ArrayVec` where we know the max number of elements * minor touchups here and there * avoid building temporary vectors that get appended to other vectors At most places I may or may not be doing the compiler's job is this PR.
2 parents 9fa9b58 + 4b80687 commit 0248c6f

File tree

16 files changed

+521
-512
lines changed

16 files changed

+521
-512
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4386,6 +4386,7 @@ dependencies = [
43864386
name = "rustdoc"
43874387
version = "0.0.0"
43884388
dependencies = [
4389+
"arrayvec",
43894390
"expect-test",
43904391
"itertools 0.9.0",
43914392
"minifier",

src/librustdoc/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2018"
88
path = "lib.rs"
99

1010
[dependencies]
11+
arrayvec = { version = "0.5.1", default-features = false }
1112
pulldown-cmark = { version = "0.8", default-features = false }
1213
minifier = "0.0.33"
1314
rayon = { version = "0.3.0", package = "rustc-rayon" }

src/librustdoc/clean/inline.rs

+10-15
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ crate fn try_inline(
5656
let kind = match res {
5757
Res::Def(DefKind::Trait, did) => {
5858
record_extern_fqn(cx, did, clean::TypeKind::Trait);
59-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
59+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
6060
clean::TraitItem(build_external_trait(cx, did))
6161
}
6262
Res::Def(DefKind::Fn, did) => {
@@ -65,27 +65,27 @@ crate fn try_inline(
6565
}
6666
Res::Def(DefKind::Struct, did) => {
6767
record_extern_fqn(cx, did, clean::TypeKind::Struct);
68-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
68+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
6969
clean::StructItem(build_struct(cx, did))
7070
}
7171
Res::Def(DefKind::Union, did) => {
7272
record_extern_fqn(cx, did, clean::TypeKind::Union);
73-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
73+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
7474
clean::UnionItem(build_union(cx, did))
7575
}
7676
Res::Def(DefKind::TyAlias, did) => {
7777
record_extern_fqn(cx, did, clean::TypeKind::Typedef);
78-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
78+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
7979
clean::TypedefItem(build_type_alias(cx, did), false)
8080
}
8181
Res::Def(DefKind::Enum, did) => {
8282
record_extern_fqn(cx, did, clean::TypeKind::Enum);
83-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
83+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
8484
clean::EnumItem(build_enum(cx, did))
8585
}
8686
Res::Def(DefKind::ForeignTy, did) => {
8787
record_extern_fqn(cx, did, clean::TypeKind::Foreign);
88-
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
88+
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
8989
clean::ForeignTypeItem
9090
}
9191
// Never inline enum variants but leave them shown as re-exports.
@@ -133,10 +133,7 @@ crate fn try_inline_glob(
133133
res: Res,
134134
visited: &mut FxHashSet<DefId>,
135135
) -> Option<Vec<clean::Item>> {
136-
if res == Res::Err {
137-
return None;
138-
}
139-
let did = res.def_id();
136+
let did = res.opt_def_id()?;
140137
if did.is_local() {
141138
return None;
142139
}
@@ -280,16 +277,14 @@ crate fn build_impls(
280277
parent_module: Option<DefId>,
281278
did: DefId,
282279
attrs: Option<Attrs<'_>>,
283-
) -> Vec<clean::Item> {
280+
ret: &mut Vec<clean::Item>,
281+
) {
284282
let tcx = cx.tcx;
285-
let mut impls = Vec::new();
286283

287284
// for each implementation of an item represented by `did`, build the clean::Item for that impl
288285
for &did in tcx.inherent_impls(did).iter() {
289-
build_impl(cx, parent_module, did, attrs, &mut impls);
286+
build_impl(cx, parent_module, did, attrs, ret);
290287
}
291-
292-
impls
293288
}
294289

295290
/// `parent_module` refers to the parent of the re-export, not the original item

src/librustdoc/clean/types.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::rc::Rc;
88
use std::sync::Arc;
99
use std::{slice, vec};
1010

11+
use arrayvec::ArrayVec;
1112
use rustc_ast::attr;
1213
use rustc_ast::util::comments::beautify_doc_string;
1314
use rustc_ast::{self as ast, AttrStyle};
@@ -16,7 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1617
use rustc_feature::UnstableFeatures;
1718
use rustc_hir as hir;
1819
use rustc_hir::def::{CtorKind, Res};
19-
use rustc_hir::def_id::{CrateNum, DefId};
20+
use rustc_hir::def_id::{CrateNum, DefId, DefIndex};
2021
use rustc_hir::lang_items::LangItem;
2122
use rustc_hir::Mutability;
2223
use rustc_index::vec::IndexVec;
@@ -28,7 +29,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
2829
use rustc_span::{self, FileName, Loc};
2930
use rustc_target::abi::VariantIdx;
3031
use rustc_target::spec::abi::Abi;
31-
use smallvec::{smallvec, SmallVec};
3232

3333
use crate::clean::cfg::Cfg;
3434
use crate::clean::external_path;
@@ -45,7 +45,7 @@ use self::ItemKind::*;
4545
use self::SelfTy::*;
4646
use self::Type::*;
4747

48-
thread_local!(crate static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
48+
thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
4949

5050
#[derive(Clone, Debug)]
5151
crate struct Crate {
@@ -293,8 +293,8 @@ impl Item {
293293
///
294294
/// [`next_def_id()`]: DocContext::next_def_id()
295295
crate fn is_fake(&self) -> bool {
296-
MAX_DEF_ID.with(|m| {
297-
m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false)
296+
MAX_DEF_IDX.with(|m| {
297+
m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
298298
})
299299
}
300300
}
@@ -1539,12 +1539,12 @@ impl PrimitiveType {
15391539
}
15401540
}
15411541

1542-
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> {
1542+
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<[DefId; 4]> {
15431543
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
15441544
}
15451545

1546-
crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> {
1547-
static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new();
1546+
crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>> {
1547+
static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>>> = OnceCell::new();
15481548

15491549
CELL.get_or_init(move || {
15501550
use self::PrimitiveType::*;
@@ -1568,7 +1568,7 @@ impl PrimitiveType {
15681568
}
15691569

15701570
let single = |a: Option<DefId>| a.into_iter().collect();
1571-
let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> {
1571+
let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_> {
15721572
a.into_iter().chain(b).collect()
15731573
};
15741574

@@ -1601,8 +1601,8 @@ impl PrimitiveType {
16011601
.collect()
16021602
},
16031603
Array => single(lang_items.array_impl()),
1604-
Tuple => smallvec![],
1605-
Unit => smallvec![],
1604+
Tuple => ArrayVec::new(),
1605+
Unit => ArrayVec::new(),
16061606
RawPointer => {
16071607
lang_items
16081608
.const_ptr_impl()
@@ -1612,9 +1612,9 @@ impl PrimitiveType {
16121612
.chain(lang_items.mut_slice_ptr_impl())
16131613
.collect()
16141614
},
1615-
Reference => smallvec![],
1616-
Fn => smallvec![],
1617-
Never => smallvec![],
1615+
Reference => ArrayVec::new(),
1616+
Fn => ArrayVec::new(),
1617+
Never => ArrayVec::new(),
16181618
}
16191619
})
16201620
}

src/librustdoc/clean/utils.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -322,20 +322,14 @@ crate fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut
322322
ItemKind::TypedefItem(ref t, true) => &t.type_,
323323
_ => continue,
324324
};
325-
let primitive = match *target {
326-
ResolvedPath { did, .. } if did.is_local() => continue,
327-
ResolvedPath { did, .. } => {
328-
ret.extend(inline::build_impls(cx, None, did, None));
329-
continue;
325+
326+
if let Some(prim) = target.primitive_type() {
327+
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
328+
inline::build_impl(cx, None, did, None, ret);
330329
}
331-
_ => match target.primitive_type() {
332-
Some(prim) => prim,
333-
None => continue,
334-
},
335-
};
336-
for &did in primitive.impls(tcx) {
330+
} else if let ResolvedPath { did, .. } = *target {
337331
if !did.is_local() {
338-
inline::build_impl(cx, None, did, None, ret);
332+
inline::build_impls(cx, None, did, None, ret);
339333
}
340334
}
341335
}

src/librustdoc/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ impl Options {
474474
};
475475

476476
let mut id_map = html::markdown::IdMap::new();
477-
id_map.populate(html::render::initial_ids());
477+
id_map.populate(&html::render::INITIAL_IDS);
478478
let external_html = match ExternalHtml::load(
479479
&matches.opt_strs("html-in-header"),
480480
&matches.opt_strs("html-before-content"),

src/librustdoc/core.rs

+30-28
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ use rustc_span::source_map;
2424
use rustc_span::symbol::sym;
2525
use rustc_span::DUMMY_SP;
2626

27-
use std::cell::{Cell, RefCell};
2827
use std::mem;
2928
use std::rc::Rc;
29+
use std::{
30+
cell::{Cell, RefCell},
31+
collections::hash_map::Entry,
32+
};
3033

3134
use crate::clean;
32-
use crate::clean::{AttributesExt, MAX_DEF_ID};
35+
use crate::clean::{AttributesExt, MAX_DEF_IDX};
3336
use crate::config::{Options as RustdocOptions, RenderOptions};
3437
use crate::config::{OutputFormat, RenderInfo};
3538
use crate::formats::cache::Cache;
@@ -63,8 +66,7 @@ crate struct DocContext<'tcx> {
6366
crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
6467
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
6568
crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
66-
crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
67-
crate all_fake_def_ids: RefCell<FxHashSet<DefId>>,
69+
crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefIndex>>,
6870
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
6971
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
7072
crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
@@ -138,37 +140,38 @@ impl<'tcx> DocContext<'tcx> {
138140
/// [`Debug`]: std::fmt::Debug
139141
/// [`clean::Item`]: crate::clean::types::Item
140142
crate fn next_def_id(&self, crate_num: CrateNum) -> DefId {
141-
let start_def_id = {
142-
let num_def_ids = if crate_num == LOCAL_CRATE {
143-
self.tcx.hir().definitions().def_path_table().num_def_ids()
144-
} else {
145-
self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
146-
};
147-
148-
DefId { krate: crate_num, index: DefIndex::from_usize(num_def_ids) }
149-
};
150-
151143
let mut fake_ids = self.fake_def_ids.borrow_mut();
152144

153-
let def_id = *fake_ids.entry(crate_num).or_insert(start_def_id);
154-
fake_ids.insert(
155-
crate_num,
156-
DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) },
157-
);
158-
159-
MAX_DEF_ID.with(|m| {
160-
m.borrow_mut().entry(def_id.krate).or_insert(start_def_id);
161-
});
162-
163-
self.all_fake_def_ids.borrow_mut().insert(def_id);
145+
let def_index = match fake_ids.entry(crate_num) {
146+
Entry::Vacant(e) => {
147+
let num_def_idx = {
148+
let num_def_idx = if crate_num == LOCAL_CRATE {
149+
self.tcx.hir().definitions().def_path_table().num_def_ids()
150+
} else {
151+
self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
152+
};
153+
154+
DefIndex::from_usize(num_def_idx)
155+
};
156+
157+
MAX_DEF_IDX.with(|m| {
158+
m.borrow_mut().insert(crate_num, num_def_idx);
159+
});
160+
e.insert(num_def_idx)
161+
}
162+
Entry::Occupied(e) => e.into_mut(),
163+
};
164+
*def_index = DefIndex::from(*def_index + 1);
164165

165-
def_id
166+
DefId { krate: crate_num, index: *def_index }
166167
}
167168

168169
/// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
169170
/// (This avoids a slice-index-out-of-bounds panic.)
170171
crate fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> {
171-
if self.all_fake_def_ids.borrow().contains(&def_id) {
172+
if MAX_DEF_IDX.with(|m| {
173+
m.borrow().get(&def_id.krate).map(|&idx| idx <= def_id.index).unwrap_or(false)
174+
}) {
172175
None
173176
} else {
174177
def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
@@ -517,7 +520,6 @@ crate fn run_global_ctxt(
517520
ct_substs: Default::default(),
518521
impl_trait_bounds: Default::default(),
519522
fake_def_ids: Default::default(),
520-
all_fake_def_ids: Default::default(),
521523
generated_synthetics: Default::default(),
522524
auto_traits: tcx
523525
.all_traits(LOCAL_CRATE)

src/librustdoc/formats/item_type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,6 @@ impl ItemType {
158158

159159
impl fmt::Display for ItemType {
160160
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161-
write!(f, "{}", self.as_str())
161+
f.write_str(self.as_str())
162162
}
163163
}

src/librustdoc/html/escape.rs

+14-17
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,20 @@ impl<'a> fmt::Display for Escape<'a> {
1616
let Escape(s) = *self;
1717
let pile_o_bits = s;
1818
let mut last = 0;
19-
for (i, ch) in s.bytes().enumerate() {
20-
match ch as char {
21-
'<' | '>' | '&' | '\'' | '"' => {
22-
fmt.write_str(&pile_o_bits[last..i])?;
23-
let s = match ch as char {
24-
'>' => "&gt;",
25-
'<' => "&lt;",
26-
'&' => "&amp;",
27-
'\'' => "&#39;",
28-
'"' => "&quot;",
29-
_ => unreachable!(),
30-
};
31-
fmt.write_str(s)?;
32-
last = i + 1;
33-
}
34-
_ => {}
35-
}
19+
for (i, ch) in s.char_indices() {
20+
let s = match ch {
21+
'>' => "&gt;",
22+
'<' => "&lt;",
23+
'&' => "&amp;",
24+
'\'' => "&#39;",
25+
'"' => "&quot;",
26+
_ => continue,
27+
};
28+
fmt.write_str(&pile_o_bits[last..i])?;
29+
fmt.write_str(s)?;
30+
// NOTE: we only expect single byte characters here - which is fine as long as we
31+
// only match single byte characters
32+
last = i + 1;
3633
}
3734

3835
if last < s.len() {

0 commit comments

Comments
 (0)