diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9272435a330a5..cc0ddf3132dac 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -374,6 +374,15 @@ macro_rules! return_if_metadata_created_in_meantime { }; } +fn check_type_name_cache(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, qualified: bool) -> String { + compute_debuginfo_type_name( + cx.tcx, + ty, + qualified, + &mut debug_context(cx).type_name_cache.borrow_mut(), + ) +} + fn fixed_vec_metadata( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId, @@ -422,7 +431,7 @@ fn vec_slice_metadata( return_if_metadata_created_in_meantime!(cx, unique_type_id); - let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true); + let slice_type_name = check_type_name_cache(cx, slice_ptr_type, true); let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); @@ -520,10 +529,10 @@ fn trait_pointer_metadata( Some(trait_object_type) => match trait_object_type.kind() { ty::Adt(def, _) => ( Some(get_namespace_for_item(cx, def.did)), - compute_debuginfo_type_name(cx.tcx, trait_object_type, false), + check_type_name_cache(cx, trait_object_type, false), ), ty::RawPtr(_) | ty::Ref(..) => { - (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true)) + (NO_SCOPE_METADATA, check_type_name_cache(cx, trait_object_type, true)) } _ => { bug!( @@ -536,7 +545,7 @@ fn trait_pointer_metadata( // No object type, use the trait type directly (no scope here since the type // will be wrapped in the dyn$ synthetic type). - None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)), + None => (NO_SCOPE_METADATA, check_type_name_cache(cx, trait_type, true)), }; let file_metadata = unknown_file_metadata(cx); @@ -987,7 +996,7 @@ fn foreign_type_metadata( ) -> &'ll DIType { debug!("foreign_type_metadata: {:?}", t); - let name = compute_debuginfo_type_name(cx.tcx, t, false); + let name = check_type_name_cache(cx, t, false); create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) } @@ -997,7 +1006,7 @@ fn pointer_type_metadata( pointee_type_metadata: &'ll DIType, ) -> &'ll DIType { let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); - let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); + let name = check_type_name_cache(cx, pointer_type, false); unsafe { llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), @@ -1300,7 +1309,7 @@ fn prepare_struct_metadata( unique_type_id: UniqueTypeId, span: Span, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); + let struct_name = check_type_name_cache(cx, struct_type, false); let (struct_def_id, variant) = match struct_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), @@ -1406,7 +1415,7 @@ fn prepare_tuple_metadata( span: Span, containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); + let tuple_name = check_type_name_cache(cx, tuple_type, false); let struct_stub = create_struct_stub( cx, @@ -1470,7 +1479,7 @@ fn prepare_union_metadata( unique_type_id: UniqueTypeId, span: Span, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); + let union_name = check_type_name_cache(cx, union_type, false); let (union_def_id, variant) = match union_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), @@ -2025,7 +2034,7 @@ fn prepare_enum_metadata( outer_field_tys: Vec>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let tcx = cx.tcx; - let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); + let enum_name = check_type_name_cache(cx, enum_type, false); let containing_scope = get_namespace_for_item(cx, enum_def_id); // FIXME: This should emit actual file metadata for the enum, but we diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index fbaf8c8bdf63d..705420e4075e4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -10,6 +10,7 @@ use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; use crate::abi::FnAbi; use crate::builder::Builder; use crate::common::CodegenCx; +use crate::debuginfo::utils::debug_context; use crate::llvm; use crate::llvm::debuginfo::{ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType, @@ -38,6 +39,7 @@ use libc::c_uint; use smallvec::SmallVec; use std::cell::RefCell; use std::iter; +use std::rc::Rc; use tracing::debug; mod create_scope_map; @@ -62,6 +64,7 @@ pub struct CrateDebugContext<'a, 'tcx> { builder: &'a mut DIBuilder<'a>, created_files: RefCell, Option), &'a DIFile>>, created_enum_disr_types: RefCell>, + type_name_cache: RefCell, bool), Rc>>, type_map: RefCell>, namespace_map: RefCell>, @@ -91,6 +94,7 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> { builder, created_files: Default::default(), created_enum_disr_types: Default::default(), + type_name_cache: Default::default(), type_map: Default::default(), namespace_map: RefCell::new(Default::default()), composite_types_completed: Default::default(), @@ -439,6 +443,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx.tcx, cx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs), name_to_append_suffix_to, + &mut debug_context(cx).type_name_cache.borrow_mut(), ); if substs.types().next().is_none() { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e842f5e9391c8..3f273e28833b9 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -11,7 +11,7 @@ // within the brackets). // * `"` is treated as the start of a string. -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -24,6 +24,7 @@ use rustc_target::abi::{Integer, TagEncoding, Variants}; use smallvec::SmallVec; use std::fmt::Write; +use std::rc::Rc; // Compute the name of the type as it should be stored in debuginfo. Does not do // any caching, i.e., calling the function twice with the same type will also do @@ -33,12 +34,20 @@ pub fn compute_debuginfo_type_name<'tcx>( tcx: TyCtxt<'tcx>, t: Ty<'tcx>, qualified: bool, + type_name_cache: &mut FxHashMap<(Ty<'tcx>, bool), Rc>, ) -> String { let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); + if let Some(type_name) = type_name_cache.get(&(t, qualified)) { + return String::from(&type_name[..]); + } + let mut result = String::with_capacity(64); let mut visited = FxHashSet::default(); - push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited); + push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited, type_name_cache); + if type_name_cache.insert((t, qualified), Rc::from(&*result)).is_some() { + bug!("type name is already in the type name cache!"); + } result } @@ -50,7 +59,13 @@ fn push_debuginfo_type_name<'tcx>( qualified: bool, output: &mut String, visited: &mut FxHashSet>, + type_name_cache: &mut FxHashMap<(Ty<'tcx>, bool), Rc>, ) { + if let Some(type_name) = type_name_cache.get(&(t, qualified)) { + output.push_str(&type_name[..]); + return; + } + // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = cpp_like_names(tcx); @@ -72,10 +87,10 @@ fn push_debuginfo_type_name<'tcx>( ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { if def.is_enum() && cpp_like_names { - msvc_enum_fallback(tcx, t, def, substs, output, visited); + msvc_enum_fallback(tcx, t, def, substs, output, visited, type_name_cache); } else { push_item_name(tcx, def.did, qualified, output); - push_generic_params_internal(tcx, substs, output, visited); + push_generic_params_internal(tcx, substs, output, visited, type_name_cache); } } ty::Tuple(component_types) => { @@ -86,7 +101,14 @@ fn push_debuginfo_type_name<'tcx>( } for component_type in component_types { - push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); + push_debuginfo_type_name( + tcx, + component_type.expect_ty(), + true, + output, + visited, + type_name_cache, + ); push_arg_separator(cpp_like_names, output); } if !component_types.is_empty() { @@ -113,7 +135,7 @@ fn push_debuginfo_type_name<'tcx>( } } - push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); + push_debuginfo_type_name(tcx, inner_type, qualified, output, visited, type_name_cache); if cpp_like_names { push_close_angle_bracket(cpp_like_names, output); @@ -139,7 +161,7 @@ fn push_debuginfo_type_name<'tcx>( } } - push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); + push_debuginfo_type_name(tcx, inner_type, qualified, output, visited, type_name_cache); if cpp_like_names && !is_slice_or_str { push_close_angle_bracket(cpp_like_names, output); @@ -148,7 +170,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Array(inner_type, len) => { if cpp_like_names { output.push_str("array$<"); - push_debuginfo_type_name(tcx, inner_type, true, output, visited); + push_debuginfo_type_name(tcx, inner_type, true, output, visited, type_name_cache); match len.val { ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(), _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all())) @@ -156,7 +178,7 @@ fn push_debuginfo_type_name<'tcx>( } } else { output.push('['); - push_debuginfo_type_name(tcx, inner_type, true, output, visited); + push_debuginfo_type_name(tcx, inner_type, true, output, visited, type_name_cache); match len.val { ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(), _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all())) @@ -171,7 +193,7 @@ fn push_debuginfo_type_name<'tcx>( output.push('['); } - push_debuginfo_type_name(tcx, inner_type, true, output, visited); + push_debuginfo_type_name(tcx, inner_type, true, output, visited, type_name_cache); if cpp_like_names { push_close_angle_bracket(cpp_like_names, output); @@ -200,8 +222,13 @@ fn push_debuginfo_type_name<'tcx>( let principal = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); push_item_name(tcx, principal.def_id, qualified, output); - let principal_has_generic_params = - push_generic_params_internal(tcx, principal.substs, output, visited); + let principal_has_generic_params = push_generic_params_internal( + tcx, + principal.substs, + output, + visited, + type_name_cache, + ); let projection_bounds: SmallVec<[_; 4]> = trait_data .projection_bounds() @@ -225,12 +252,26 @@ fn push_debuginfo_type_name<'tcx>( output.push_str("assoc$<"); push_item_name(tcx, item_def_id, false, output); push_arg_separator(cpp_like_names, output); - push_debuginfo_type_name(tcx, ty, true, output, visited); + push_debuginfo_type_name( + tcx, + ty, + true, + output, + visited, + type_name_cache, + ); push_close_angle_bracket(cpp_like_names, output); } else { push_item_name(tcx, item_def_id, false, output); output.push('='); - push_debuginfo_type_name(tcx, ty, true, output, visited); + push_debuginfo_type_name( + tcx, + ty, + true, + output, + visited, + type_name_cache, + ); } } @@ -298,7 +339,14 @@ fn push_debuginfo_type_name<'tcx>( if sig.output().is_unit() { output.push_str("void"); } else { - push_debuginfo_type_name(tcx, sig.output(), true, output, visited); + push_debuginfo_type_name( + tcx, + sig.output(), + true, + output, + visited, + type_name_cache, + ); } output.push_str(" (*)("); } else { @@ -315,7 +363,14 @@ fn push_debuginfo_type_name<'tcx>( if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { - push_debuginfo_type_name(tcx, parameter_type, true, output, visited); + push_debuginfo_type_name( + tcx, + parameter_type, + true, + output, + visited, + type_name_cache, + ); push_arg_separator(cpp_like_names, output); } pop_arg_separator(output); @@ -333,7 +388,7 @@ fn push_debuginfo_type_name<'tcx>( if !cpp_like_names && !sig.output().is_unit() { output.push_str(" -> "); - push_debuginfo_type_name(tcx, sig.output(), true, output, visited); + push_debuginfo_type_name(tcx, sig.output(), true, output, visited, type_name_cache); } // We only keep the type in 'visited' @@ -386,12 +441,13 @@ fn push_debuginfo_type_name<'tcx>( substs: SubstsRef<'tcx>, output: &mut String, visited: &mut FxHashSet>, + type_name_cache: &mut FxHashMap<(Ty<'tcx>, bool), Rc>, ) { let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error"); output.push_str("enum$<"); push_item_name(tcx, def.did, true, output); - push_generic_params_internal(tcx, substs, output, visited); + push_generic_params_internal(tcx, substs, output, visited, type_name_cache); if let Variants::Multiple { tag_encoding: TagEncoding::Niche { dataful_variant, .. }, @@ -503,6 +559,7 @@ fn push_generic_params_internal<'tcx>( substs: SubstsRef<'tcx>, output: &mut String, visited: &mut FxHashSet>, + type_name_cache: &mut FxHashMap<(Ty<'tcx>, bool), Rc>, ) -> bool { if substs.non_erasable_generics().next().is_none() { return false; @@ -517,7 +574,14 @@ fn push_generic_params_internal<'tcx>( for type_parameter in substs.non_erasable_generics() { match type_parameter { GenericArgKind::Type(type_parameter) => { - push_debuginfo_type_name(tcx, type_parameter, true, output, visited); + push_debuginfo_type_name( + tcx, + type_parameter, + true, + output, + visited, + type_name_cache, + ); } GenericArgKind::Const(ct) => { push_const_param(tcx, ct, output); @@ -578,10 +642,15 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: .unwrap(); } -pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) { +pub fn push_generic_params<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + output: &mut String, + type_name_cache: &mut FxHashMap<(Ty<'tcx>, bool), Rc>, +) { let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); let mut visited = FxHashSet::default(); - push_generic_params_internal(tcx, substs, output, &mut visited); + push_generic_params_internal(tcx, substs, output, &mut visited, type_name_cache); } fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) {