Don't unnecessarily clone some fields in Context

There was no need to clone `id_map` because it was reset before each
item was rendered. `deref_id_map` was not reset, but it was keyed by
`DefId` and thus was unlikely to have collisions (at least for now).

Now we just clone the fields that need to be cloned, and instead create
fresh versions of the others.
This commit is contained in:
Camelid 2021-03-01 19:12:03 -08:00
parent ff39c46959
commit c09d9d34f0
5 changed files with 28 additions and 22 deletions

View File

@ -9,7 +9,7 @@
/// Allows for different backends to rustdoc to be used with the `run_format()` function. Each
/// backend renderer has hooks for initialization, documenting an item, entering and exiting a
/// module, and cleanup/finalizing output.
crate trait FormatRenderer<'tcx>: Clone {
crate trait FormatRenderer<'tcx>: Sized {
/// Gives a description of the renderer. Used for performance profiling.
fn descr() -> &'static str;
@ -23,6 +23,9 @@ fn init(
tcx: TyCtxt<'tcx>,
) -> Result<(Self, clean::Crate), Error>;
/// Make a new renderer to render a child of the item currently being rendered.
fn make_child_renderer(&self) -> Self;
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
fn item(&mut self, item: clean::Item) -> Result<(), Error>;
@ -67,7 +70,7 @@ fn after_krate(
item.name = Some(krate.name);
// Render the crate documentation
let mut work = vec![(format_renderer.clone(), item)];
let mut work = vec![(format_renderer.make_child_renderer(), item)];
let unknown = rustc_span::Symbol::intern("<unknown item>");
while let Some((mut cx, item)) = work.pop() {
@ -87,7 +90,7 @@ fn after_krate(
};
for it in module.items {
debug!("Adding {:?} to worklist", it.name);
work.push((cx.clone(), it));
work.push((cx.make_child_renderer(), it));
}
cx.mod_item_out(&name)?;

View File

@ -1373,10 +1373,6 @@ pub fn new() -> Self {
}
}
crate fn reset(&mut self) {
self.map = init_id_map();
}
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(),

View File

@ -38,15 +38,9 @@ fn test_unique_id() {
"assoc_type.Item-1",
];
let map = RefCell::new(IdMap::new());
let test = || {
let mut map = map.borrow_mut();
let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
assert_eq!(&actual[..], expected);
};
test();
map.borrow_mut().reset();
test();
let mut map = IdMap::new();
let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
assert_eq!(&actual[..], expected);
}
#[test]

View File

@ -40,7 +40,6 @@
/// It is intended that this context is a lightweight object which can be fairly
/// easily cloned because it is cloned per work-job (about once per item in the
/// rustdoc tree).
#[derive(Clone)]
crate struct Context<'tcx> {
/// Current hierarchy of components leading down to what's currently being
/// rendered
@ -157,11 +156,6 @@ fn render_item(&self, it: &clean::Item, pushname: bool) -> String {
static_extra_scripts: &[],
};
{
self.id_map.borrow_mut().reset();
self.id_map.borrow_mut().populate(&INITIAL_IDS);
}
if !self.render_redirect_pages {
layout::render(
&self.shared.layout,
@ -436,6 +430,21 @@ fn init(
Ok((cx, krate))
}
fn make_child_renderer(&self) -> Self {
let mut id_map = IdMap::new();
id_map.populate(&INITIAL_IDS);
Self {
current: self.current.clone(),
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
id_map: Box::new(RefCell::new(id_map)),
deref_id_map: Box::new(RefCell::new(FxHashMap::default())),
shared: Rc::clone(&self.shared),
cache: Rc::clone(&self.cache),
}
}
fn after_krate(
&mut self,
krate: &clean::Crate,

View File

@ -149,6 +149,10 @@ fn init(
))
}
fn make_child_renderer(&self) -> Self {
self.clone()
}
/// Inserts an item into the index. This should be used rather than directly calling insert on
/// the hashmap because certain items (traits and types) need to have their mappings for trait
/// implementations filled out before they're inserted.