Auto merge of #130857 - lukas-code:no-clones-allowed, r=notriddle
rustdoc perf: clone `clean::Item` less In https://github.com/rust-lang/rust/pull/130798, I caused a small perf regression for rustdoc (see https://github.com/rust-lang/rust/pull/130807#issuecomment-2373116917), 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.
This commit is contained in:
commit
a3f76a26e0
@ -837,8 +837,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did)
|
if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -850,6 +849,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
|
|||||||
debug!("record_extern_trait: {did:?}");
|
debug!("record_extern_trait: {did:?}");
|
||||||
let trait_ = build_external_trait(cx, did);
|
let trait_ = build_external_trait(cx, did);
|
||||||
|
|
||||||
cx.external_traits.borrow_mut().insert(did, trait_);
|
cx.external_traits.insert(did, trait_);
|
||||||
cx.active_extern_traits.remove(&did);
|
cx.active_extern_traits.remove(&did);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::{Arc, OnceLock as OnceCell};
|
use std::sync::{Arc, OnceLock as OnceCell};
|
||||||
use std::{fmt, iter};
|
use std::{fmt, iter};
|
||||||
|
|
||||||
@ -115,7 +113,7 @@ impl From<DefId> for ItemId {
|
|||||||
pub(crate) struct Crate {
|
pub(crate) struct Crate {
|
||||||
pub(crate) module: Item,
|
pub(crate) module: Item,
|
||||||
/// Only here so that they can be filtered through the rustdoc passes.
|
/// Only here so that they can be filtered through the rustdoc passes.
|
||||||
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
|
pub(crate) external_traits: Box<FxHashMap<DefId, Trait>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Crate {
|
impl Crate {
|
||||||
|
@ -74,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Crate { module, external_traits: cx.external_traits.clone() }
|
Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clean_middle_generic_args<'tcx>(
|
pub(crate) fn clean_middle_generic_args<'tcx>(
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
use std::{io, mem};
|
use std::{io, mem};
|
||||||
@ -41,7 +39,7 @@ pub(crate) struct DocContext<'tcx> {
|
|||||||
/// Most of this logic is copied from rustc_lint::late.
|
/// Most of this logic is copied from rustc_lint::late.
|
||||||
pub(crate) param_env: ParamEnv<'tcx>,
|
pub(crate) param_env: ParamEnv<'tcx>,
|
||||||
/// Later on moved through `clean::Crate` into `cache`
|
/// Later on moved through `clean::Crate` into `cache`
|
||||||
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
|
pub(crate) external_traits: FxHashMap<DefId, clean::Trait>,
|
||||||
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
|
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
|
||||||
/// the same time.
|
/// the same time.
|
||||||
pub(crate) active_extern_traits: DefIdSet,
|
pub(crate) active_extern_traits: DefIdSet,
|
||||||
@ -359,7 +357,7 @@ pub(crate) fn run_global_ctxt(
|
|||||||
// Note that in case of `#![no_core]`, the trait is not available.
|
// Note that in case of `#![no_core]`, the trait is not available.
|
||||||
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
|
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
|
||||||
let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
|
let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
|
||||||
ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
|
ctxt.external_traits.insert(sized_trait_did, sized_trait);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("crate: {:?}", tcx.hir().krate());
|
debug!("crate: {:?}", tcx.hir().krate());
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::mem;
|
||||||
|
|
||||||
use crate::clean::*;
|
use crate::clean::*;
|
||||||
|
|
||||||
pub(crate) fn strip_item(mut item: Item) -> Item {
|
pub(crate) fn strip_item(mut item: Item) -> Item {
|
||||||
@ -116,10 +118,11 @@ pub(crate) trait DocFolder: Sized {
|
|||||||
fn fold_crate(&mut self, mut c: Crate) -> Crate {
|
fn fold_crate(&mut self, mut c: Crate) -> Crate {
|
||||||
c.module = self.fold_item(c.module).unwrap();
|
c.module = self.fold_item(c.module).unwrap();
|
||||||
|
|
||||||
let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
|
for trait_ in c.external_traits.values_mut() {
|
||||||
for (k, mut v) in external_traits {
|
trait_.items = mem::take(&mut trait_.items)
|
||||||
v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
|
.into_iter()
|
||||||
c.external_traits.borrow_mut().insert(k, v);
|
.filter_map(|i| self.fold_item(i))
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
c
|
c
|
||||||
|
@ -153,7 +153,8 @@ impl Cache {
|
|||||||
|
|
||||||
// Crawl the crate to build various caches used for the output
|
// Crawl the crate to build various caches used for the output
|
||||||
debug!(?cx.cache.crate_version);
|
debug!(?cx.cache.crate_version);
|
||||||
cx.cache.traits = krate.external_traits.take();
|
assert!(cx.external_traits.is_empty());
|
||||||
|
cx.cache.traits = mem::take(&mut krate.external_traits);
|
||||||
|
|
||||||
// Cache where all our extern crates are located
|
// Cache where all our extern crates are located
|
||||||
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
|
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
|
||||||
|
@ -824,9 +824,9 @@ impl Serialize for Implementor {
|
|||||||
/// this visitor works to reverse that: `aliased_types` is a map
|
/// this visitor works to reverse that: `aliased_types` is a map
|
||||||
/// from target to the aliases that reference it, and each one
|
/// from target to the aliases that reference it, and each one
|
||||||
/// will generate one file.
|
/// will generate one file.
|
||||||
struct TypeImplCollector<'cx, 'cache> {
|
struct TypeImplCollector<'cx, 'cache, 'item> {
|
||||||
/// Map from DefId-of-aliased-type to its data.
|
/// Map from DefId-of-aliased-type to its data.
|
||||||
aliased_types: IndexMap<DefId, AliasedType<'cache>>,
|
aliased_types: IndexMap<DefId, AliasedType<'cache, 'item>>,
|
||||||
visited_aliases: FxHashSet<DefId>,
|
visited_aliases: FxHashSet<DefId>,
|
||||||
cache: &'cache Cache,
|
cache: &'cache Cache,
|
||||||
cx: &'cache mut Context<'cx>,
|
cx: &'cache mut Context<'cx>,
|
||||||
@ -847,26 +847,26 @@ struct TypeImplCollector<'cx, 'cache> {
|
|||||||
/// ]
|
/// ]
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
struct AliasedType<'cache> {
|
struct AliasedType<'cache, 'item> {
|
||||||
/// This is used to generate the actual filename of this aliased type.
|
/// This is used to generate the actual filename of this aliased type.
|
||||||
target_fqp: &'cache [Symbol],
|
target_fqp: &'cache [Symbol],
|
||||||
target_type: ItemType,
|
target_type: ItemType,
|
||||||
/// This is the data stored inside the file.
|
/// This is the data stored inside the file.
|
||||||
/// ItemId is used to deduplicate impls.
|
/// ItemId is used to deduplicate impls.
|
||||||
impl_: IndexMap<ItemId, AliasedTypeImpl<'cache>>,
|
impl_: IndexMap<ItemId, AliasedTypeImpl<'cache, 'item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `impl_` contains data that's used to figure out if an alias will work,
|
/// The `impl_` contains data that's used to figure out if an alias will work,
|
||||||
/// and to generate the HTML at the end.
|
/// and to generate the HTML at the end.
|
||||||
///
|
///
|
||||||
/// The `type_aliases` list is built up with each type alias that matches.
|
/// The `type_aliases` list is built up with each type alias that matches.
|
||||||
struct AliasedTypeImpl<'cache> {
|
struct AliasedTypeImpl<'cache, 'item> {
|
||||||
impl_: &'cache Impl,
|
impl_: &'cache Impl,
|
||||||
type_aliases: Vec<(&'cache [Symbol], Item)>,
|
type_aliases: Vec<(&'cache [Symbol], &'item Item)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> {
|
impl<'cx, 'cache, 'item> DocVisitor<'item> for TypeImplCollector<'cx, 'cache, 'item> {
|
||||||
fn visit_item(&mut self, it: &Item) {
|
fn visit_item(&mut self, it: &'item Item) {
|
||||||
self.visit_item_recur(it);
|
self.visit_item_recur(it);
|
||||||
let cache = self.cache;
|
let cache = self.cache;
|
||||||
let ItemKind::TypeAliasItem(ref t) = it.kind else { return };
|
let ItemKind::TypeAliasItem(ref t) = it.kind else { return };
|
||||||
@ -927,7 +927,7 @@ impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// This impl was not found in the set of rejected impls
|
// This impl was not found in the set of rejected impls
|
||||||
aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone()));
|
aliased_type_impl.type_aliases.push((&self_fqp[..], it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ impl LocalSourcesCollector<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocVisitor for LocalSourcesCollector<'_, '_> {
|
impl DocVisitor<'_> for LocalSourcesCollector<'_, '_> {
|
||||||
fn visit_item(&mut self, item: &clean::Item) {
|
fn visit_item(&mut self, item: &clean::Item) {
|
||||||
self.add_local_source(item);
|
self.add_local_source(item);
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ struct SourceCollector<'a, 'tcx> {
|
|||||||
crate_name: &'a str,
|
crate_name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocVisitor for SourceCollector<'_, '_> {
|
impl DocVisitor<'_> for SourceCollector<'_, '_> {
|
||||||
fn visit_item(&mut self, item: &clean::Item) {
|
fn visit_item(&mut self, item: &clean::Item) {
|
||||||
if !self.cx.include_sources {
|
if !self.cx.include_sources {
|
||||||
return;
|
return;
|
||||||
|
@ -187,7 +187,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
|
impl<'a, 'b> DocVisitor<'_> for CoverageCalculator<'a, 'b> {
|
||||||
fn visit_item(&mut self, i: &clean::Item) {
|
fn visit_item(&mut self, i: &clean::Item) {
|
||||||
if !i.item_id.is_local() {
|
if !i.item_id.is_local() {
|
||||||
// non-local items are skipped because they can be out of the users control,
|
// non-local items are skipped because they can be out of the users control,
|
||||||
|
@ -34,7 +34,7 @@ pub(crate) fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -
|
|||||||
krate
|
krate
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> {
|
impl<'a, 'tcx> DocVisitor<'_> for DocTestVisibilityLinter<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &Item) {
|
fn visit_item(&mut self, item: &Item) {
|
||||||
look_for_tests(self.cx, &item.doc_value(), item);
|
look_for_tests(self.cx, &item.doc_value(), item);
|
||||||
|
|
||||||
|
@ -816,7 +816,7 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<Vec<(Res, T)>, ResolutionFailu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
|
impl<'a, 'tcx> DocVisitor<'_> for LinkCollector<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &Item) {
|
fn visit_item(&mut self, item: &Item) {
|
||||||
self.resolve_links(item);
|
self.resolve_links(item);
|
||||||
self.visit_item_recur(item)
|
self.visit_item_recur(item)
|
||||||
|
@ -219,6 +219,8 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
|
|||||||
panic!("collect-trait-impls can't run");
|
panic!("collect-trait-impls can't run");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
krate.external_traits.extend(cx.external_traits.drain());
|
||||||
|
|
||||||
krate
|
krate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +229,7 @@ struct SyntheticImplCollector<'a, 'tcx> {
|
|||||||
impls: Vec<Item>,
|
impls: Vec<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
|
impl<'a, 'tcx> DocVisitor<'_> for SyntheticImplCollector<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, i: &Item) {
|
fn visit_item(&mut self, i: &Item) {
|
||||||
if i.is_struct() || i.is_enum() || i.is_union() {
|
if i.is_struct() || i.is_enum() || i.is_union() {
|
||||||
// FIXME(eddyb) is this `doc(hidden)` check needed?
|
// FIXME(eddyb) is this `doc(hidden)` check needed?
|
||||||
@ -254,7 +256,7 @@ impl<'cache> ItemAndAliasCollector<'cache> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cache> DocVisitor for ItemAndAliasCollector<'cache> {
|
impl<'cache> DocVisitor<'_> for ItemAndAliasCollector<'cache> {
|
||||||
fn visit_item(&mut self, i: &Item) {
|
fn visit_item(&mut self, i: &Item) {
|
||||||
self.items.insert(i.item_id);
|
self.items.insert(i.item_id);
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ pub(crate) fn run_lints(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
|||||||
krate
|
krate
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
|
impl<'a, 'tcx> DocVisitor<'_> for Linter<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &Item) {
|
fn visit_item(&mut self, item: &Item) {
|
||||||
let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id) else {
|
let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id) else {
|
||||||
// If non-local, no need to check anything.
|
// If non-local, no need to check anything.
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::clean::*;
|
use crate::clean::*;
|
||||||
|
|
||||||
pub(crate) trait DocVisitor: Sized {
|
pub(crate) trait DocVisitor<'a>: Sized {
|
||||||
fn visit_item(&mut self, item: &Item) {
|
fn visit_item(&mut self, item: &'a Item) {
|
||||||
self.visit_item_recur(item)
|
self.visit_item_recur(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// don't override!
|
/// don't override!
|
||||||
fn visit_inner_recur(&mut self, kind: &ItemKind) {
|
fn visit_inner_recur(&mut self, kind: &'a ItemKind) {
|
||||||
match kind {
|
match kind {
|
||||||
StrippedItem(..) => unreachable!(),
|
StrippedItem(..) => unreachable!(),
|
||||||
ModuleItem(i) => {
|
ModuleItem(i) => {
|
||||||
@ -47,25 +47,22 @@ pub(crate) trait DocVisitor: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// don't override!
|
/// don't override!
|
||||||
fn visit_item_recur(&mut self, item: &Item) {
|
fn visit_item_recur(&mut self, item: &'a Item) {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
StrippedItem(i) => self.visit_inner_recur(&*i),
|
StrippedItem(i) => self.visit_inner_recur(&*i),
|
||||||
_ => self.visit_inner_recur(&item.kind),
|
_ => self.visit_inner_recur(&item.kind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_mod(&mut self, m: &Module) {
|
fn visit_mod(&mut self, m: &'a Module) {
|
||||||
m.items.iter().for_each(|i| self.visit_item(i))
|
m.items.iter().for_each(|i| self.visit_item(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_crate(&mut self, c: &Crate) {
|
fn visit_crate(&mut self, c: &'a Crate) {
|
||||||
self.visit_item(&c.module);
|
self.visit_item(&c.module);
|
||||||
|
|
||||||
// FIXME: make this a simple by-ref for loop once external_traits is cleaned up
|
for trait_ in c.external_traits.values() {
|
||||||
let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
|
trait_.items.iter().for_each(|i| self.visit_item(i));
|
||||||
for (k, v) in external_traits {
|
|
||||||
v.items.iter().for_each(|i| self.visit_item(i));
|
|
||||||
c.external_traits.borrow_mut().insert(k, v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user