Skip to content

Commit a522d78

Browse files
committed
Auto merge of #133345 - GuillaumeGomez:stop-cloning-context, r=notriddle,aDotInTheVoid
Stop cloning `Context` so much This is a first step for #82381. It's already big enough so I'll continue in a follow-up once this PR is merged. Next step will be to get rid of `SharedContext` by inlining it directly into `Context`. cc `@camelid` r? `@notriddle`
2 parents 5e1440a + 69ed026 commit a522d78

File tree

9 files changed

+355
-285
lines changed

9 files changed

+355
-285
lines changed

src/librustdoc/formats/renderer.rs

+63-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
use rustc_data_structures::profiling::SelfProfilerRef;
12
use rustc_middle::ty::TyCtxt;
2-
use tracing::debug;
33

44
use crate::clean;
55
use crate::config::RenderOptions;
@@ -17,6 +17,18 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
1717
///
1818
/// This is true for html, and false for json. See #80664
1919
const RUN_ON_MODULE: bool;
20+
/// This associated type is the type where the current module information is stored.
21+
///
22+
/// For each module, we go through their items by calling for each item:
23+
///
24+
/// 1. save_module_data
25+
/// 2. item
26+
/// 3. set_back_info
27+
///
28+
/// However,the `item` method might update information in `self` (for example if the child is
29+
/// a module). To prevent it to impact the other children of the current module, we need to
30+
/// reset the information between each call to `item` by using `set_back_info`.
31+
type ModuleData;
2032

2133
/// Sets up any state required for the renderer. When this is called the cache has already been
2234
/// populated.
@@ -27,8 +39,20 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
2739
tcx: TyCtxt<'tcx>,
2840
) -> Result<(Self, clean::Crate), Error>;
2941

30-
/// Make a new renderer to render a child of the item currently being rendered.
31-
fn make_child_renderer(&self) -> Self;
42+
/// This method is called right before call [`Self::item`]. This method returns a type
43+
/// containing information that needs to be reset after the [`Self::item`] method has been
44+
/// called with the [`Self::set_back_info`] method.
45+
///
46+
/// In short it goes like this:
47+
///
48+
/// ```ignore (not valid code)
49+
/// let reset_data = type.save_module_data();
50+
/// type.item(item)?;
51+
/// type.set_back_info(reset_data);
52+
/// ```
53+
fn save_module_data(&mut self) -> Self::ModuleData;
54+
/// Used to reset current module's information.
55+
fn set_back_info(&mut self, info: Self::ModuleData);
3256

3357
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
3458
fn item(&mut self, item: clean::Item) -> Result<(), Error>;
@@ -47,6 +71,40 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
4771
fn cache(&self) -> &Cache;
4872
}
4973

74+
fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>(
75+
cx: &mut T,
76+
item: clean::Item,
77+
prof: &SelfProfilerRef,
78+
) -> Result<(), Error> {
79+
if item.is_mod() && T::RUN_ON_MODULE {
80+
// modules are special because they add a namespace. We also need to
81+
// recurse into the items of the module as well.
82+
let _timer =
83+
prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
84+
85+
cx.mod_item_in(&item)?;
86+
let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) =
87+
item.inner.kind
88+
else {
89+
unreachable!()
90+
};
91+
for it in module.items {
92+
let info = cx.save_module_data();
93+
run_format_inner(cx, it, prof)?;
94+
cx.set_back_info(info);
95+
}
96+
97+
cx.mod_item_out()?;
98+
// FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
99+
// cases. Use an explicit match instead.
100+
} else if let Some(item_name) = item.name
101+
&& !item.is_extern_crate()
102+
{
103+
prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?;
104+
}
105+
Ok(())
106+
}
107+
50108
/// Main method for rendering a crate.
51109
pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
52110
krate: clean::Crate,
@@ -66,36 +124,8 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
66124
}
67125

68126
// Render the crate documentation
69-
let mut work = vec![(format_renderer.make_child_renderer(), krate.module)];
70-
71-
while let Some((mut cx, item)) = work.pop() {
72-
if item.is_mod() && T::RUN_ON_MODULE {
73-
// modules are special because they add a namespace. We also need to
74-
// recurse into the items of the module as well.
75-
let _timer =
76-
prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
77-
78-
cx.mod_item_in(&item)?;
79-
let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) =
80-
item.inner.kind
81-
else {
82-
unreachable!()
83-
};
84-
for it in module.items {
85-
debug!("Adding {:?} to worklist", it.name);
86-
work.push((cx.make_child_renderer(), it));
87-
}
88-
89-
cx.mod_item_out()?;
90-
// FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
91-
// cases. Use an explicit match instead.
92-
} else if let Some(item_name) = item.name
93-
&& !item.is_extern_crate()
94-
{
95-
prof.generic_activity_with_arg("render_item", item_name.as_str())
96-
.run(|| cx.item(item))?;
97-
}
98-
}
127+
run_format_inner(&mut format_renderer, krate.module, prof)?;
128+
99129
prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr())
100130
.run(|| format_renderer.after_krate())
101131
}

src/librustdoc/html/markdown.rs

+66-51
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use std::sync::OnceLock;
3737
use pulldown_cmark::{
3838
BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html,
3939
};
40-
use rustc_data_structures::fx::FxHashMap;
40+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4141
use rustc_errors::{Diag, DiagMessage};
4242
use rustc_hir::def_id::LocalDefId;
4343
use rustc_middle::ty::TyCtxt;
@@ -1886,71 +1886,81 @@ pub struct IdMap {
18861886
existing_footnotes: usize,
18871887
}
18881888

1889-
// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
1890-
static DEFAULT_ID_MAP: OnceLock<FxHashMap<Cow<'static, str>, usize>> = OnceLock::new();
1889+
// The map is pre-initialized and then can be used as is to prevent cloning it for each item
1890+
// (in the sidebar rendering).
1891+
static DEFAULT_ID_MAP: OnceLock<FxHashSet<&'static str>> = OnceLock::new();
18911892

1892-
fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
1893-
let mut map = FxHashMap::default();
1893+
fn init_id_map() -> FxHashSet<&'static str> {
1894+
let mut map = FxHashSet::default();
18941895
// This is the list of IDs used in JavaScript.
1895-
map.insert("help".into(), 1);
1896-
map.insert("settings".into(), 1);
1897-
map.insert("not-displayed".into(), 1);
1898-
map.insert("alternative-display".into(), 1);
1899-
map.insert("search".into(), 1);
1900-
map.insert("crate-search".into(), 1);
1901-
map.insert("crate-search-div".into(), 1);
1896+
map.insert("help");
1897+
map.insert("settings");
1898+
map.insert("not-displayed");
1899+
map.insert("alternative-display");
1900+
map.insert("search");
1901+
map.insert("crate-search");
1902+
map.insert("crate-search-div");
19021903
// This is the list of IDs used in HTML generated in Rust (including the ones
19031904
// used in tera template files).
1904-
map.insert("themeStyle".into(), 1);
1905-
map.insert("settings-menu".into(), 1);
1906-
map.insert("help-button".into(), 1);
1907-
map.insert("sidebar-button".into(), 1);
1908-
map.insert("main-content".into(), 1);
1909-
map.insert("toggle-all-docs".into(), 1);
1910-
map.insert("all-types".into(), 1);
1911-
map.insert("default-settings".into(), 1);
1912-
map.insert("sidebar-vars".into(), 1);
1913-
map.insert("copy-path".into(), 1);
1914-
map.insert("rustdoc-toc".into(), 1);
1915-
map.insert("rustdoc-modnav".into(), 1);
1905+
map.insert("themeStyle");
1906+
map.insert("settings-menu");
1907+
map.insert("help-button");
1908+
map.insert("sidebar-button");
1909+
map.insert("main-content");
1910+
map.insert("toggle-all-docs");
1911+
map.insert("all-types");
1912+
map.insert("default-settings");
1913+
map.insert("sidebar-vars");
1914+
map.insert("copy-path");
1915+
map.insert("rustdoc-toc");
1916+
map.insert("rustdoc-modnav");
19161917
// This is the list of IDs used by rustdoc sections (but still generated by
19171918
// rustdoc).
1918-
map.insert("fields".into(), 1);
1919-
map.insert("variants".into(), 1);
1920-
map.insert("implementors-list".into(), 1);
1921-
map.insert("synthetic-implementors-list".into(), 1);
1922-
map.insert("foreign-impls".into(), 1);
1923-
map.insert("implementations".into(), 1);
1924-
map.insert("trait-implementations".into(), 1);
1925-
map.insert("synthetic-implementations".into(), 1);
1926-
map.insert("blanket-implementations".into(), 1);
1927-
map.insert("required-associated-types".into(), 1);
1928-
map.insert("provided-associated-types".into(), 1);
1929-
map.insert("provided-associated-consts".into(), 1);
1930-
map.insert("required-associated-consts".into(), 1);
1931-
map.insert("required-methods".into(), 1);
1932-
map.insert("provided-methods".into(), 1);
1933-
map.insert("dyn-compatibility".into(), 1);
1934-
map.insert("implementors".into(), 1);
1935-
map.insert("synthetic-implementors".into(), 1);
1936-
map.insert("implementations-list".into(), 1);
1937-
map.insert("trait-implementations-list".into(), 1);
1938-
map.insert("synthetic-implementations-list".into(), 1);
1939-
map.insert("blanket-implementations-list".into(), 1);
1940-
map.insert("deref-methods".into(), 1);
1941-
map.insert("layout".into(), 1);
1942-
map.insert("aliased-type".into(), 1);
1919+
map.insert("fields");
1920+
map.insert("variants");
1921+
map.insert("implementors-list");
1922+
map.insert("synthetic-implementors-list");
1923+
map.insert("foreign-impls");
1924+
map.insert("implementations");
1925+
map.insert("trait-implementations");
1926+
map.insert("synthetic-implementations");
1927+
map.insert("blanket-implementations");
1928+
map.insert("required-associated-types");
1929+
map.insert("provided-associated-types");
1930+
map.insert("provided-associated-consts");
1931+
map.insert("required-associated-consts");
1932+
map.insert("required-methods");
1933+
map.insert("provided-methods");
1934+
map.insert("dyn-compatibility");
1935+
map.insert("implementors");
1936+
map.insert("synthetic-implementors");
1937+
map.insert("implementations-list");
1938+
map.insert("trait-implementations-list");
1939+
map.insert("synthetic-implementations-list");
1940+
map.insert("blanket-implementations-list");
1941+
map.insert("deref-methods");
1942+
map.insert("layout");
1943+
map.insert("aliased-type");
19431944
map
19441945
}
19451946

19461947
impl IdMap {
19471948
pub fn new() -> Self {
1948-
IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone(), existing_footnotes: 0 }
1949+
IdMap { map: FxHashMap::default(), existing_footnotes: 0 }
19491950
}
19501951

19511952
pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
19521953
let id = match self.map.get_mut(candidate.as_ref()) {
1953-
None => candidate.to_string(),
1954+
None => {
1955+
let candidate = candidate.to_string();
1956+
if DEFAULT_ID_MAP.get_or_init(init_id_map).contains(candidate.as_str()) {
1957+
let id = format!("{}-{}", candidate, 1);
1958+
self.map.insert(candidate.into(), 2);
1959+
id
1960+
} else {
1961+
candidate
1962+
}
1963+
}
19541964
Some(a) => {
19551965
let id = format!("{}-{}", candidate.as_ref(), *a);
19561966
*a += 1;
@@ -1970,4 +1980,9 @@ impl IdMap {
19701980
closure(self, &mut existing_footnotes);
19711981
self.existing_footnotes = existing_footnotes;
19721982
}
1983+
1984+
pub(crate) fn clear(&mut self) {
1985+
self.map.clear();
1986+
self.existing_footnotes = 0;
1987+
}
19731988
}

0 commit comments

Comments
 (0)