Skip to content

Commit a3f76a2

Browse files
committed
Auto merge of rust-lang#130857 - lukas-code:no-clones-allowed, r=notriddle
rustdoc perf: clone `clean::Item` less In rust-lang#130798, I caused a small perf regression for rustdoc (see rust-lang#130807 (comment)), so here is a small improvement to make up for it 😺. This change is actually unrelated to the minor perf regression in `Item::stability` and instead fixes a more relevant perf problem that I found while investigating: For certain crates with many impls on type aliases, we unnecessarily cloned large `clean::Item`s multiple times -- now we just borrow them.
2 parents b9dc4a3 + 345077a commit a3f76a2

File tree

14 files changed

+42
-44
lines changed

14 files changed

+42
-44
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -837,8 +837,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
837837
}
838838

839839
{
840-
if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did)
841-
{
840+
if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) {
842841
return;
843842
}
844843
}
@@ -850,6 +849,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
850849
debug!("record_extern_trait: {did:?}");
851850
let trait_ = build_external_trait(cx, did);
852851

853-
cx.external_traits.borrow_mut().insert(did, trait_);
852+
cx.external_traits.insert(did, trait_);
854853
cx.active_extern_traits.remove(&did);
855854
}

src/librustdoc/clean/types.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::borrow::Cow;
2-
use std::cell::RefCell;
32
use std::hash::Hash;
43
use std::path::PathBuf;
5-
use std::rc::Rc;
64
use std::sync::{Arc, OnceLock as OnceCell};
75
use std::{fmt, iter};
86

@@ -115,7 +113,7 @@ impl From<DefId> for ItemId {
115113
pub(crate) struct Crate {
116114
pub(crate) module: Item,
117115
/// Only here so that they can be filtered through the rustdoc passes.
118-
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
116+
pub(crate) external_traits: Box<FxHashMap<DefId, Trait>>,
119117
}
120118

121119
impl Crate {

src/librustdoc/clean/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
7474
}));
7575
}
7676

77-
Crate { module, external_traits: cx.external_traits.clone() }
77+
Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) }
7878
}
7979

8080
pub(crate) fn clean_middle_generic_args<'tcx>(

src/librustdoc/core.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::cell::RefCell;
2-
use std::rc::Rc;
31
use std::sync::atomic::AtomicBool;
42
use std::sync::{Arc, LazyLock};
53
use std::{io, mem};
@@ -41,7 +39,7 @@ pub(crate) struct DocContext<'tcx> {
4139
/// Most of this logic is copied from rustc_lint::late.
4240
pub(crate) param_env: ParamEnv<'tcx>,
4341
/// Later on moved through `clean::Crate` into `cache`
44-
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
42+
pub(crate) external_traits: FxHashMap<DefId, clean::Trait>,
4543
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
4644
/// the same time.
4745
pub(crate) active_extern_traits: DefIdSet,
@@ -359,7 +357,7 @@ pub(crate) fn run_global_ctxt(
359357
// Note that in case of `#![no_core]`, the trait is not available.
360358
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
361359
let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
362-
ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
360+
ctxt.external_traits.insert(sized_trait_did, sized_trait);
363361
}
364362

365363
debug!("crate: {:?}", tcx.hir().krate());

src/librustdoc/fold.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::mem;
2+
13
use crate::clean::*;
24

35
pub(crate) fn strip_item(mut item: Item) -> Item {
@@ -116,10 +118,11 @@ pub(crate) trait DocFolder: Sized {
116118
fn fold_crate(&mut self, mut c: Crate) -> Crate {
117119
c.module = self.fold_item(c.module).unwrap();
118120

119-
let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
120-
for (k, mut v) in external_traits {
121-
v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
122-
c.external_traits.borrow_mut().insert(k, v);
121+
for trait_ in c.external_traits.values_mut() {
122+
trait_.items = mem::take(&mut trait_.items)
123+
.into_iter()
124+
.filter_map(|i| self.fold_item(i))
125+
.collect();
123126
}
124127

125128
c

src/librustdoc/formats/cache.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ impl Cache {
153153

154154
// Crawl the crate to build various caches used for the output
155155
debug!(?cx.cache.crate_version);
156-
cx.cache.traits = krate.external_traits.take();
156+
assert!(cx.external_traits.is_empty());
157+
cx.cache.traits = mem::take(&mut krate.external_traits);
157158

158159
// Cache where all our extern crates are located
159160
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code

src/librustdoc/html/render/write_shared.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -824,9 +824,9 @@ impl Serialize for Implementor {
824824
/// this visitor works to reverse that: `aliased_types` is a map
825825
/// from target to the aliases that reference it, and each one
826826
/// will generate one file.
827-
struct TypeImplCollector<'cx, 'cache> {
827+
struct TypeImplCollector<'cx, 'cache, 'item> {
828828
/// Map from DefId-of-aliased-type to its data.
829-
aliased_types: IndexMap<DefId, AliasedType<'cache>>,
829+
aliased_types: IndexMap<DefId, AliasedType<'cache, 'item>>,
830830
visited_aliases: FxHashSet<DefId>,
831831
cache: &'cache Cache,
832832
cx: &'cache mut Context<'cx>,
@@ -847,26 +847,26 @@ struct TypeImplCollector<'cx, 'cache> {
847847
/// ]
848848
/// )
849849
/// ```
850-
struct AliasedType<'cache> {
850+
struct AliasedType<'cache, 'item> {
851851
/// This is used to generate the actual filename of this aliased type.
852852
target_fqp: &'cache [Symbol],
853853
target_type: ItemType,
854854
/// This is the data stored inside the file.
855855
/// ItemId is used to deduplicate impls.
856-
impl_: IndexMap<ItemId, AliasedTypeImpl<'cache>>,
856+
impl_: IndexMap<ItemId, AliasedTypeImpl<'cache, 'item>>,
857857
}
858858

859859
/// The `impl_` contains data that's used to figure out if an alias will work,
860860
/// and to generate the HTML at the end.
861861
///
862862
/// The `type_aliases` list is built up with each type alias that matches.
863-
struct AliasedTypeImpl<'cache> {
863+
struct AliasedTypeImpl<'cache, 'item> {
864864
impl_: &'cache Impl,
865-
type_aliases: Vec<(&'cache [Symbol], Item)>,
865+
type_aliases: Vec<(&'cache [Symbol], &'item Item)>,
866866
}
867867

868-
impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> {
869-
fn visit_item(&mut self, it: &Item) {
868+
impl<'cx, 'cache, 'item> DocVisitor<'item> for TypeImplCollector<'cx, 'cache, 'item> {
869+
fn visit_item(&mut self, it: &'item Item) {
870870
self.visit_item_recur(it);
871871
let cache = self.cache;
872872
let ItemKind::TypeAliasItem(ref t) = it.kind else { return };
@@ -927,7 +927,7 @@ impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> {
927927
continue;
928928
}
929929
// This impl was not found in the set of rejected impls
930-
aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone()));
930+
aliased_type_impl.type_aliases.push((&self_fqp[..], it));
931931
}
932932
}
933933
}

src/librustdoc/html/sources.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl LocalSourcesCollector<'_, '_> {
103103
}
104104
}
105105

106-
impl DocVisitor for LocalSourcesCollector<'_, '_> {
106+
impl DocVisitor<'_> for LocalSourcesCollector<'_, '_> {
107107
fn visit_item(&mut self, item: &clean::Item) {
108108
self.add_local_source(item);
109109

@@ -122,7 +122,7 @@ struct SourceCollector<'a, 'tcx> {
122122
crate_name: &'a str,
123123
}
124124

125-
impl DocVisitor for SourceCollector<'_, '_> {
125+
impl DocVisitor<'_> for SourceCollector<'_, '_> {
126126
fn visit_item(&mut self, item: &clean::Item) {
127127
if !self.cx.include_sources {
128128
return;

src/librustdoc/passes/calculate_doc_coverage.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
187187
}
188188
}
189189

190-
impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
190+
impl<'a, 'b> DocVisitor<'_> for CoverageCalculator<'a, 'b> {
191191
fn visit_item(&mut self, i: &clean::Item) {
192192
if !i.item_id.is_local() {
193193
// non-local items are skipped because they can be out of the users control,

src/librustdoc/passes/check_doc_test_visibility.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub(crate) fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -
3434
krate
3535
}
3636

37-
impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> {
37+
impl<'a, 'tcx> DocVisitor<'_> for DocTestVisibilityLinter<'a, 'tcx> {
3838
fn visit_item(&mut self, item: &Item) {
3939
look_for_tests(self.cx, &item.doc_value(), item);
4040

0 commit comments

Comments
 (0)