From d31d71e7b867e5271ee1cb10de0b201c5063ee0e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 23 Jan 2023 22:45:42 +0400 Subject: [PATCH] [perf] WIP --- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 + .../src/rmeta/decoder/cstore_impl.rs | 4 + compiler/rustc_metadata/src/rmeta/encoder.rs | 136 ++++++++++++++---- compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + src/librustdoc/clean/utils.rs | 8 +- src/librustdoc/visit_lib.rs | 2 +- 7 files changed, 124 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 44da3fbe300ca..e1bb3d786f1de 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1240,6 +1240,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } + fn get_rustdoc_reachable(self) -> impl Iterator + 'a { + self.root.rustdoc_reachable.decode(self) + } + fn get_native_libraries(self, sess: &'a Session) -> impl Iterator + 'a { self.root.native_libraries.decode((self, sess)) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2fa645cd9e33d..0642585281b16 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -624,6 +624,10 @@ impl CStore { self.get_crate_data(cnum).get_all_incoherent_impls() } + pub fn rustdoc_reachable_untracked(&self, cnum: CrateNum) -> impl Iterator + '_ { + self.get_crate_data(cnum).get_rustdoc_reachable() + } + pub fn associated_item_def_ids_untracked<'a>( &'a self, def_id: DefId, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2ecaa33d4d315..e56cdf14eaa88 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -5,7 +5,7 @@ use crate::rmeta::*; use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; @@ -598,6 +598,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let incoherent_impls = stat!("incoherent-impls", || self.encode_incoherent_impls()); + let rustdoc_reachable = stat!("rustdoc-reachable", || self.encode_rustdoc_reachable()); + _ = stat!("mir", || self.encode_mir()); _ = stat!("items", || { @@ -698,6 +700,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { traits, impls, incoherent_impls, + rustdoc_reachable, exported_symbols, interpret_alloc_index, tables, @@ -1256,7 +1259,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) { + fn module_children( + tcx: TyCtxt<'tcx>, + md: &'tcx hir::Mod<'tcx>, + ) -> impl Iterator + 'tcx { + iter::from_generator(move || { + for item_id in md.item_ids { + match tcx.hir().item(*item_id).kind { + // Foreign items are planted into their parent modules + // from name resolution point of view. + hir::ItemKind::ForeignMod { items, .. } => { + for foreign_item in items { + yield foreign_item.id.owner_id.def_id.local_def_index; + } + } + // Only encode named non-reexport children, reexports are encoded + // separately and unnamed items are not used by name resolution. + hir::ItemKind::ExternCrate(..) => continue, + hir::ItemKind::Struct(ref vdata, _) => { + yield item_id.owner_id.def_id.local_def_index; + // Encode constructors which take a separate slot in value namespace. + if let Some(ctor_hir_id) = vdata.ctor_hir_id() { + yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; + } + } + _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { + yield item_id.owner_id.def_id.local_def_index; + } + _ => continue, + } + } + }) + } + + fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &'tcx hir::Mod<'tcx>) { let tcx = self.tcx; let def_id = local_def_id.to_def_id(); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); @@ -1270,33 +1306,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { - record_array!(self.tables.children[def_id] <- iter::from_generator(|| { - for item_id in md.item_ids { - match tcx.hir().item(*item_id).kind { - // Foreign items are planted into their parent modules - // from name resolution point of view. - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - yield foreign_item.id.owner_id.def_id.local_def_index; - } - } - // Only encode named non-reexport children, reexports are encoded - // separately and unnamed items are not used by name resolution. - hir::ItemKind::ExternCrate(..) => continue, - hir::ItemKind::Struct(ref vdata, _) => { - yield item_id.owner_id.def_id.local_def_index; - // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_hir_id) = vdata.ctor_hir_id() { - yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; - } - } - _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { - yield item_id.owner_id.def_id.local_def_index; - } - _ => continue, - } - } - })); + record_array!(self.tables.children[def_id] <- Self::module_children(tcx, md)); if let Some(reexports) = tcx.module_reexports(local_def_id) { assert!(!reexports.is_empty()); @@ -1974,6 +1984,74 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(&all_impls) } + fn encode_rustdoc_reachable(&mut self) -> LazyArray { + struct LibEmbargoVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + extern_public: FxHashSet, + visited_mods: FxHashSet, + } + + impl LibEmbargoVisitor<'_> { + fn visit_mod(&mut self, def_id: DefId) { + if !self.visited_mods.insert(def_id) { + return; + } + + let tcx = self.tcx; + match def_id.as_local() { + Some(def_id) => { + let (md, ..) = tcx.hir().get_module(def_id); + for local_def_index in EncodeContext::module_children(tcx, md) { + let def_id = LocalDefId { local_def_index }.to_def_id(); + if tcx.visibility(def_id).is_public() { + self.visit_item(def_id); + } + } + if let Some(reexports) = tcx.module_reexports(def_id) { + for item in reexports { + if let Some(def_id) = item.res.opt_def_id() { + if item.vis.is_public() { + self.visit_item(def_id); + } + } + } + } + } + None => { + for item in tcx.module_children(def_id).iter() { + if let Some(def_id) = item.res.opt_def_id() { + if item.vis.is_public() { + self.visit_item(def_id); + } + } + } + } + } + } + + fn visit_item(&mut self, def_id: DefId) { + if !self.tcx.is_doc_hidden(def_id) { + self.extern_public.insert(def_id); + if self.tcx.def_kind(def_id) == DefKind::Mod { + self.visit_mod(def_id); + } + } + } + } + + let mut visitor = LibEmbargoVisitor { + tcx: self.tcx, + extern_public: Default::default(), + visited_mods: Default::default(), + }; + visitor.visit_item(CRATE_DEF_ID.to_def_id()); + + let mut rustdoc_reachable: Vec<_> = visitor.extern_public.into_iter().collect(); + rustdoc_reachable.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); + + self.lazy_array(rustdoc_reachable) + } + // Encodes all symbols exported from this crate into the metadata. // // This pass is seeded off the reachability list calculated in the diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 69690264ae4ea..2f28808459a91 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -239,6 +239,7 @@ pub(crate) struct CrateRoot { traits: LazyArray, impls: LazyArray, incoherent_impls: LazyArray, + rustdoc_reachable: LazyArray, interpret_alloc_index: LazyArray, proc_macro_data: Option, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 24f3d1acff188..e0b55c972d89d 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -81,6 +81,7 @@ trivially_parameterized_over_tcx! { rustc_hir::IsAsync, rustc_hir::LangItem, rustc_hir::def::DefKind, + rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_index::bit_set::BitSet, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a12f764fa8e3b..dafbbe2503156 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::TokenTree; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_metadata::creader::CStore; use rustc_middle::mir; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; @@ -29,9 +30,12 @@ mod tests; pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { let module = crate::visit_ast::RustdocVisitor::new(cx).visit(); + let cstore = CStore::from_tcx(cx.tcx); for &cnum in cx.tcx.crates(()) { - // Analyze doc-reachability for extern items - crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id()); + Extend::extend( + &mut cx.cache.effective_visibilities.extern_public, + cstore.rustdoc_reachable_untracked(cnum), + ); } // Clean the crate, translating the entire librustc_ast AST to one that is diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index fd4f9254107ca..1fa651b4d59b9 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt; #[derive(Default)] pub(crate) struct RustdocEffectiveVisibilities { - extern_public: DefIdSet, + pub extern_public: DefIdSet, } macro_rules! define_method {