-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Stop cloning Context
so much
#133345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stop cloning Context
so much
#133345
Changes from all commits
8047340
46afbc0
2e242f8
5fa1653
5f9e716
e60a7a4
b492170
69ed026
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,7 @@ use std::sync::OnceLock; | |
use pulldown_cmark::{ | ||
BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html, | ||
}; | ||
use rustc_data_structures::fx::FxHashMap; | ||
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | ||
use rustc_errors::{Diag, DiagMessage}; | ||
use rustc_hir::def_id::LocalDefId; | ||
use rustc_middle::ty::TyCtxt; | ||
|
@@ -1886,71 +1886,81 @@ pub struct IdMap { | |
existing_footnotes: usize, | ||
} | ||
|
||
// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly. | ||
static DEFAULT_ID_MAP: OnceLock<FxHashMap<Cow<'static, str>, usize>> = OnceLock::new(); | ||
// The map is pre-initialized and then can be used as is to prevent cloning it for each item | ||
// (in the sidebar rendering). | ||
static DEFAULT_ID_MAP: OnceLock<FxHashSet<&'static str>> = OnceLock::new(); | ||
|
||
fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { | ||
let mut map = FxHashMap::default(); | ||
fn init_id_map() -> FxHashSet<&'static str> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does performance compare if this is a function that returns bool? fn is_builtin_id(id: &str) -> bool {
match id {
// This is the list of IDs used in JavaScript.
| "help"
| "settings"
| "not-displayed"
| "alternative-display"
| "search"
| "crate-search"
| "crate-search-div"
// This is the list of IDs used in HTML generated in Rust (including the ones
// used in tera template files).
| "themeStyle"
| "settings-menu"
| "help-button"
| "sidebar-button"
| "main-content"
| "toggle-all-docs"
| "all-types"
| "default-settings"
| "sidebar-vars"
| "copy-path"
| "rustdoc-toc"
| "rustdoc-modnav"
// This is the list of IDs used by rustdoc sections (but still generated by
// rustdoc).
| "fields"
| "variants"
| "implementors-list"
| "synthetic-implementors-list"
| "foreign-impls"
| "implementations"
| "trait-implementations"
| "synthetic-implementations"
| "blanket-implementations"
| "required-associated-types"
| "provided-associated-types"
| "provided-associated-consts"
| "required-associated-consts"
| "required-methods"
| "provided-methods"
| "dyn-compatibility"
| "implementors"
| "synthetic-implementors"
| "implementations-list"
| "trait-implementations-list"
| "synthetic-implementations-list"
| "blanket-implementations-list"
| "deref-methods"
| "layout"
| "aliased-type"
=> true,
_ => false,
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fine. It can be tried as a follow-up PR. |
||
let mut map = FxHashSet::default(); | ||
// This is the list of IDs used in JavaScript. | ||
map.insert("help".into(), 1); | ||
map.insert("settings".into(), 1); | ||
map.insert("not-displayed".into(), 1); | ||
map.insert("alternative-display".into(), 1); | ||
map.insert("search".into(), 1); | ||
map.insert("crate-search".into(), 1); | ||
map.insert("crate-search-div".into(), 1); | ||
map.insert("help"); | ||
map.insert("settings"); | ||
map.insert("not-displayed"); | ||
map.insert("alternative-display"); | ||
map.insert("search"); | ||
map.insert("crate-search"); | ||
map.insert("crate-search-div"); | ||
// This is the list of IDs used in HTML generated in Rust (including the ones | ||
// used in tera template files). | ||
map.insert("themeStyle".into(), 1); | ||
map.insert("settings-menu".into(), 1); | ||
map.insert("help-button".into(), 1); | ||
map.insert("sidebar-button".into(), 1); | ||
map.insert("main-content".into(), 1); | ||
map.insert("toggle-all-docs".into(), 1); | ||
map.insert("all-types".into(), 1); | ||
map.insert("default-settings".into(), 1); | ||
map.insert("sidebar-vars".into(), 1); | ||
map.insert("copy-path".into(), 1); | ||
map.insert("rustdoc-toc".into(), 1); | ||
map.insert("rustdoc-modnav".into(), 1); | ||
map.insert("themeStyle"); | ||
map.insert("settings-menu"); | ||
map.insert("help-button"); | ||
map.insert("sidebar-button"); | ||
map.insert("main-content"); | ||
map.insert("toggle-all-docs"); | ||
map.insert("all-types"); | ||
map.insert("default-settings"); | ||
map.insert("sidebar-vars"); | ||
map.insert("copy-path"); | ||
map.insert("rustdoc-toc"); | ||
map.insert("rustdoc-modnav"); | ||
// This is the list of IDs used by rustdoc sections (but still generated by | ||
// rustdoc). | ||
map.insert("fields".into(), 1); | ||
map.insert("variants".into(), 1); | ||
map.insert("implementors-list".into(), 1); | ||
map.insert("synthetic-implementors-list".into(), 1); | ||
map.insert("foreign-impls".into(), 1); | ||
map.insert("implementations".into(), 1); | ||
map.insert("trait-implementations".into(), 1); | ||
map.insert("synthetic-implementations".into(), 1); | ||
map.insert("blanket-implementations".into(), 1); | ||
map.insert("required-associated-types".into(), 1); | ||
map.insert("provided-associated-types".into(), 1); | ||
map.insert("provided-associated-consts".into(), 1); | ||
map.insert("required-associated-consts".into(), 1); | ||
map.insert("required-methods".into(), 1); | ||
map.insert("provided-methods".into(), 1); | ||
map.insert("dyn-compatibility".into(), 1); | ||
map.insert("implementors".into(), 1); | ||
map.insert("synthetic-implementors".into(), 1); | ||
map.insert("implementations-list".into(), 1); | ||
map.insert("trait-implementations-list".into(), 1); | ||
map.insert("synthetic-implementations-list".into(), 1); | ||
map.insert("blanket-implementations-list".into(), 1); | ||
map.insert("deref-methods".into(), 1); | ||
map.insert("layout".into(), 1); | ||
map.insert("aliased-type".into(), 1); | ||
map.insert("fields"); | ||
map.insert("variants"); | ||
map.insert("implementors-list"); | ||
map.insert("synthetic-implementors-list"); | ||
map.insert("foreign-impls"); | ||
map.insert("implementations"); | ||
map.insert("trait-implementations"); | ||
map.insert("synthetic-implementations"); | ||
map.insert("blanket-implementations"); | ||
map.insert("required-associated-types"); | ||
map.insert("provided-associated-types"); | ||
map.insert("provided-associated-consts"); | ||
map.insert("required-associated-consts"); | ||
map.insert("required-methods"); | ||
map.insert("provided-methods"); | ||
map.insert("dyn-compatibility"); | ||
map.insert("implementors"); | ||
map.insert("synthetic-implementors"); | ||
map.insert("implementations-list"); | ||
map.insert("trait-implementations-list"); | ||
map.insert("synthetic-implementations-list"); | ||
map.insert("blanket-implementations-list"); | ||
map.insert("deref-methods"); | ||
map.insert("layout"); | ||
map.insert("aliased-type"); | ||
map | ||
} | ||
|
||
impl IdMap { | ||
pub fn new() -> Self { | ||
IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone(), existing_footnotes: 0 } | ||
IdMap { map: FxHashMap::default(), existing_footnotes: 0 } | ||
} | ||
|
||
pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String { | ||
let id = match self.map.get_mut(candidate.as_ref()) { | ||
None => candidate.to_string(), | ||
None => { | ||
let candidate = candidate.to_string(); | ||
if DEFAULT_ID_MAP.get_or_init(init_id_map).contains(candidate.as_str()) { | ||
let id = format!("{}-{}", candidate, 1); | ||
self.map.insert(candidate.into(), 2); | ||
id | ||
} else { | ||
candidate | ||
} | ||
} | ||
Some(a) => { | ||
let id = format!("{}-{}", candidate.as_ref(), *a); | ||
*a += 1; | ||
|
@@ -1970,4 +1980,9 @@ impl IdMap { | |
closure(self, &mut existing_footnotes); | ||
self.existing_footnotes = existing_footnotes; | ||
} | ||
|
||
pub(crate) fn clear(&mut self) { | ||
self.map.clear(); | ||
self.existing_footnotes = 0; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old version used a heap-allocated stack, and this version instead uses the call stack.
I think that's fine, as long as you call stacker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering we recurse on modules (other items, they stop at one level), I think we're on the safe side. Do you see a case where it could be an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's going to be a problem. I just noticed that the old didn't do this.
If you don't think it's a problem, then we can go ahead with it. There might be other spots where rustdoc directly recurses on modules anyway.