Auto merge of #93644 - michaelwoerister:simpler-debuginfo-typemap, r=wesleywiser

debuginfo: Simplify TypeMap used during LLVM debuginfo generation.

This PR simplifies the TypeMap that is used in `rustc_codegen_llvm::debuginfo::metadata`. It was unnecessarily complicated because it was originally implemented when types were not yet normalized before codegen. So it did it's own normalization and kept track of multiple unnormalized types being mapped to a single unique id.

This PR is based on https://github.com/rust-lang/rust/pull/93503, which is not merged yet.

The PR also removes the arena used for allocating string ids and instead uses `InlinableString` from the [inlinable_string](https://crates.io/crates/inlinable_string) crate. That might not be the best choice, since that crate does not seem to be very actively maintained. The [flexible-string](https://crates.io/crates/flexible-string) crate would be an alternative.

r? `@ghost`
This commit is contained in:
bors 2022-02-25 11:00:32 +00:00
commit 9b2a46591a
6 changed files with 254 additions and 352 deletions

View file

@ -3524,6 +3524,7 @@ dependencies = [
"rustc_hir",
"rustc_index",
"rustc_llvm",
"rustc_macros",
"rustc_metadata",
"rustc_middle",
"rustc_query_system",

View file

@ -25,6 +25,7 @@ rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_llvm = { path = "../rustc_llvm" }
rustc_macros = { path = "../rustc_macros" }
rustc_metadata = { path = "../rustc_metadata" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }

View file

@ -23,9 +23,7 @@
use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_fs_util::path_to_c_string;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@ -37,7 +35,6 @@
use rustc_middle::ty::{
self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
};
use rustc_query_system::ich::NodeIdHashingMode;
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::Symbol;
use rustc_span::FileNameDisplayPreference;
@ -45,9 +42,11 @@
use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
use smallvec::SmallVec;
use tracing::debug;
use libc::{c_longlong, c_uint};
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
@ -95,193 +94,127 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
pub const NO_SCOPE_METADATA: Option<&DIScope> = None;
mod unique_type_id {
use super::*;
use rustc_arena::DroplessArena;
use rustc_data_structures::{
fingerprint::Fingerprint,
stable_hasher::{HashStable, NodeIdHashingMode, StableHasher},
};
use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
#[derive(Copy, Hash, Eq, PartialEq, Clone)]
pub(super) struct UniqueTypeId(u32);
// The `&'static str`s in this type actually point into the arena.
//
// The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
// found that to regress performance up to 2% in some cases. This might be
// revisited after further improvements to `indexmap`.
#[derive(Default)]
pub(super) struct TypeIdInterner {
arena: DroplessArena,
names: FxHashMap<&'static str, UniqueTypeId>,
strings: Vec<&'static str>,
// This type cannot be constructed outside of this module because
// it has a private field. We make use of this in order to prevent
// `UniqueTypeId` from being constructed directly, without asserting
// the preconditions.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
pub struct HiddenZst {
_inaccessible: (),
}
impl TypeIdInterner {
#[inline]
pub(super) fn intern(&mut self, string: &str) -> UniqueTypeId {
if let Some(&name) = self.names.get(string) {
return name;
}
/// A unique identifier for anything that we create a debuginfo node for.
/// The types it contains are expected to already be normalized (which
/// is debug_asserted in the constructors).
///
/// Note that there are some things that only show up in debuginfo, like
/// the separate type descriptions for each enum variant. These get an ID
/// too because they have their own debuginfo node in LLVM IR.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
pub(super) enum UniqueTypeId<'tcx> {
/// The ID of a regular type as it shows up at the language level.
Ty(Ty<'tcx>, HiddenZst),
/// The ID for the artificial struct type describing a single enum variant.
Variant(Ty<'tcx>, VariantIdx, HiddenZst),
/// The ID for the single DW_TAG_variant_part nested inside the top-level
/// DW_TAG_structure_type that describes enums and generators.
VariantPart(Ty<'tcx>, HiddenZst),
/// The ID of the artificial type we create for VTables.
VTableTy(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>, HiddenZst),
}
let name = UniqueTypeId(self.strings.len() as u32);
// `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
// UTF-8.
let string: &str =
unsafe { std::str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) };
// It is safe to extend the arena allocation to `'static` because we only access
// these while the arena is still alive.
let string: &'static str = unsafe { &*(string as *const str) };
self.strings.push(string);
self.names.insert(string, name);
name
impl<'tcx> UniqueTypeId<'tcx> {
pub fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self {
debug_assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t));
UniqueTypeId::Ty(t, HiddenZst { _inaccessible: () })
}
// Get the symbol as a string. `Symbol::as_str()` should be used in
// preference to this function.
pub(super) fn get(&self, symbol: UniqueTypeId) -> &str {
self.strings[symbol.0 as usize]
pub fn for_enum_variant(
tcx: TyCtxt<'tcx>,
enum_ty: Ty<'tcx>,
variant_idx: VariantIdx,
) -> Self {
debug_assert_eq!(
enum_ty,
tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)
);
UniqueTypeId::Variant(enum_ty, variant_idx, HiddenZst { _inaccessible: () })
}
pub fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self {
debug_assert_eq!(
enum_ty,
tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)
);
UniqueTypeId::VariantPart(enum_ty, HiddenZst { _inaccessible: () })
}
pub fn for_vtable_ty(
tcx: TyCtxt<'tcx>,
self_type: Ty<'tcx>,
implemented_trait: Option<PolyExistentialTraitRef<'tcx>>,
) -> Self {
debug_assert_eq!(
self_type,
tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type)
);
debug_assert_eq!(
implemented_trait,
tcx.normalize_erasing_regions(ParamEnv::reveal_all(), implemented_trait)
);
UniqueTypeId::VTableTy(self_type, implemented_trait, HiddenZst { _inaccessible: () })
}
/// Generates a string version of this [UniqueTypeId], which can be used as the `UniqueId`
/// argument of the various `LLVMRustDIBuilderCreate*Type()` methods.
///
/// Right now this takes the form of a hex-encoded opaque hash value.
pub fn generate_unique_id_string(&self, tcx: TyCtxt<'tcx>) -> String {
let mut hasher = StableHasher::new();
let mut hcx = tcx.create_stable_hashing_context();
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
self.hash_stable(hcx, &mut hasher);
});
});
hasher.finish::<Fingerprint>().to_hex()
}
}
}
use unique_type_id::*;
/// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes
/// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for
/// faster lookup, also by `Ty`. The `TypeMap` is responsible for creating
/// `UniqueTypeId`s.
/// The `TypeMap` is where the debug context holds the type metadata nodes
/// created so far. The metadata nodes are indexed by `UniqueTypeId`.
#[derive(Default)]
pub struct TypeMap<'ll, 'tcx> {
/// The `UniqueTypeId`s created so far.
unique_id_interner: TypeIdInterner,
/// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping.
unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>,
/// A map from types to debuginfo metadata. This is an N:1 mapping.
type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
/// A map from types to `UniqueTypeId`. This is an N:1 mapping.
type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>,
unique_id_to_metadata: RefCell<FxHashMap<UniqueTypeId<'tcx>, &'ll DIType>>,
}
impl<'ll, 'tcx> TypeMap<'ll, 'tcx> {
/// Adds a Ty to metadata mapping to the TypeMap. The method will fail if
/// the mapping already exists.
fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType) {
if self.type_to_metadata.insert(type_, metadata).is_some() {
bug!("type metadata for `Ty` '{}' is already in the `TypeMap`!", type_);
}
}
/// Removes a `Ty`-to-metadata mapping.
/// This is useful when computing the metadata for a potentially
/// recursive type (e.g., a function pointer of the form:
///
/// fn foo() -> impl Copy { foo }
///
/// This kind of type cannot be properly represented
/// via LLVM debuginfo. As a workaround,
/// we register a temporary Ty to metadata mapping
/// for the function before we compute its actual metadata.
/// If the metadata computation ends up recursing back to the
/// original function, it will use the temporary mapping
/// for the inner self-reference, preventing us from
/// recursing forever.
///
/// This function is used to remove the temporary metadata
/// mapping after we've computed the actual metadata.
fn remove_type(&mut self, ty: Ty<'tcx>) {
if self.type_to_metadata.remove(&ty).is_none() {
bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", ty);
}
}
/// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will
/// fail if the mapping already exists.
fn register_unique_id_with_metadata(
&mut self,
unique_type_id: UniqueTypeId,
&self,
unique_type_id: UniqueTypeId<'tcx>,
metadata: &'ll DIType,
) {
if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() {
bug!(
"type metadata for unique ID '{}' is already in the `TypeMap`!",
self.get_unique_type_id_as_string(unique_type_id)
);
if self.unique_id_to_metadata.borrow_mut().insert(unique_type_id, metadata).is_some() {
bug!("type metadata for unique ID '{:?}' is already in the `TypeMap`!", unique_type_id);
}
}
fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<&'ll DIType> {
self.type_to_metadata.get(&type_).cloned()
}
fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<&'ll DIType> {
self.unique_id_to_metadata.get(&unique_type_id).cloned()
}
/// Gets the string representation of a `UniqueTypeId`. This method will fail if
/// the ID is unknown.
fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str {
self.unique_id_interner.get(unique_type_id)
}
/// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given
/// type has been requested before, this is just a table lookup. Otherwise, an
/// ID will be generated and stored for later lookup.
fn get_unique_type_id_of_type<'a>(
&mut self,
cx: &CodegenCx<'a, 'tcx>,
type_: Ty<'tcx>,
) -> UniqueTypeId {
// Let's see if we already have something in the cache.
if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() {
return unique_type_id;
}
// If not, generate one.
// The hasher we are using to generate the UniqueTypeId. We want
// something that provides more than the 64 bits of the DefaultHasher.
let mut hasher = StableHasher::new();
let mut hcx = cx.tcx.create_stable_hashing_context();
let type_ = cx.tcx.erase_regions(type_);
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
type_.hash_stable(hcx, &mut hasher);
});
});
let unique_type_id = hasher.finish::<Fingerprint>().to_hex();
let key = self.unique_id_interner.intern(&unique_type_id);
self.type_to_unique_id.insert(type_, key);
key
}
/// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really
/// types of their own, so they need special handling. We still need a
/// `UniqueTypeId` for them, since to debuginfo they *are* real types.
fn get_unique_type_id_of_enum_variant<'a>(
&mut self,
cx: &CodegenCx<'a, 'tcx>,
enum_type: Ty<'tcx>,
variant_name: &str,
) -> UniqueTypeId {
let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
let enum_variant_type_id =
format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name);
let interner_key = self.unique_id_interner.intern(&enum_variant_type_id);
interner_key
}
/// Gets the unique type ID string for an enum variant part.
/// Variant parts are not types and shouldn't really have their own ID,
/// but it makes `set_members_of_composite_type()` simpler.
fn get_unique_type_id_str_of_enum_variant_part(
&mut self,
enum_type_id: UniqueTypeId,
) -> String {
format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id))
}
/// Gets the `UniqueTypeId` for the type of a vtable.
fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId {
let interner_key = self.unique_id_interner.intern(vtable_type_name);
interner_key
fn find_metadata_for_unique_id(
&self,
unique_type_id: UniqueTypeId<'tcx>,
) -> Option<&'ll DIType> {
self.unique_id_to_metadata.borrow().get(&unique_type_id).cloned()
}
}
@ -293,7 +226,7 @@ fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> Uniqu
enum RecursiveTypeDescription<'ll, 'tcx> {
UnfinishedMetadata {
unfinished_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
metadata_stub: &'ll DICompositeType,
member_holding_stub: &'ll DICompositeType,
member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
@ -304,15 +237,13 @@ enum RecursiveTypeDescription<'ll, 'tcx> {
fn create_and_register_recursive_type_forward_declaration<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unfinished_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
metadata_stub: &'ll DICompositeType,
member_holding_stub: &'ll DICompositeType,
member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
// Insert the stub into the `TypeMap` in order to allow for recursive references.
let mut type_map = debug_context(cx).type_map.borrow_mut();
type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub);
type_map.register_type_with_metadata(unfinished_type, metadata_stub);
debug_context(cx).type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub);
UnfinishedMetadata {
unfinished_type,
@ -344,9 +275,10 @@ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
// `create_and_register_recursive_type_forward_declaration()`
// function.
{
let type_map = debug_context(cx).type_map.borrow();
if type_map.find_metadata_for_unique_id(unique_type_id).is_none()
|| type_map.find_metadata_for_type(unfinished_type).is_none()
if debug_context(cx)
.type_map
.find_metadata_for_unique_id(unique_type_id)
.is_none()
{
bug!(
"Forward declaration of potentially recursive type \
@ -379,7 +311,7 @@ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
macro_rules! return_if_metadata_created_in_meantime {
($cx: expr, $unique_type_id: expr) => {
if let Some(metadata) =
debug_context($cx).type_map.borrow().find_metadata_for_unique_id($unique_type_id)
debug_context($cx).type_map.find_metadata_for_unique_id($unique_type_id)
{
return MetadataCreationResult::new(metadata, true);
}
@ -390,7 +322,7 @@ macro_rules! return_if_metadata_created_in_meantime {
/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata].
fn fixed_size_array_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
array_type: Ty<'tcx>,
) -> MetadataCreationResult<'ll> {
let ty::Array(element_type, len) = array_type.kind() else {
@ -434,7 +366,7 @@ fn pointer_or_reference_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ptr_type: Ty<'tcx>,
pointee_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> MetadataCreationResult<'ll> {
let pointee_type_metadata = type_metadata(cx, pointee_type);
@ -534,16 +466,42 @@ fn pointer_or_reference_metadata<'ll, 'tcx>(
fn subroutine_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
signature: ty::PolyFnSig<'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
) -> MetadataCreationResult<'ll> {
let signature =
cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature);
// It's possible to create a self-referential
// type in Rust by using 'impl trait':
//
// fn foo() -> impl Copy { foo }
//
// Unfortunately LLVM's API does not allow us to create recursive subroutine types.
// In order to work around that restriction we place a marker type in the type map,
// before creating the actual type. If the actual type is recursive, it will hit the
// marker type. So we end up with a type that looks like
//
// fn foo() -> <recursive_type>
//
// Once that is created, we replace the marker in the typemap with the actual type.
debug_context(cx)
.type_map
.unique_id_to_metadata
.borrow_mut()
.insert(unique_type_id, recursion_marker_type(cx));
let signature_metadata: Vec<_> = iter::once(
let UniqueTypeId::Ty(fn_ty, _) = unique_type_id else {
bug!("subroutine_type_metadata() called with unexpected input type: {:?}", unique_type_id)
};
let signature = cx
.tcx
.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), fn_ty.fn_sig(cx.tcx));
let signature_metadata: SmallVec<[_; 32]> = iter::once(
// return type
match signature.output().kind() {
ty::Tuple(tys) if tys.is_empty() => None,
ty::Tuple(tys) if tys.is_empty() => {
// this is a "void" function
None
}
_ => Some(type_metadata(cx, signature.output())),
},
)
@ -553,17 +511,30 @@ fn subroutine_type_metadata<'ll, 'tcx>(
)
.collect();
return_if_metadata_created_in_meantime!(cx, unique_type_id);
debug_context(cx).type_map.unique_id_to_metadata.borrow_mut().remove(&unique_type_id);
MetadataCreationResult::new(
unsafe {
llvm::LLVMRustDIBuilderCreateSubroutineType(
DIB(cx),
create_DIArray(DIB(cx), &signature_metadata[..]),
)
},
false,
)
let fn_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateSubroutineType(
DIB(cx),
create_DIArray(DIB(cx), &signature_metadata[..]),
)
};
// This is actually a function pointer, so wrap it in pointer DI.
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
let metadata = unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
fn_metadata,
cx.tcx.data_layout.pointer_size.bits(),
cx.tcx.data_layout.pointer_align.abi.bits() as u32,
0, // Ignore DWARF address space.
name.as_ptr().cast(),
name.len(),
)
};
MetadataCreationResult::new(metadata, false)
}
/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
@ -571,7 +542,7 @@ fn subroutine_type_metadata<'ll, 'tcx>(
fn dyn_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
dyn_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> &'ll DIType {
if let ty::Dynamic(..) = dyn_type.kind() {
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
@ -601,7 +572,7 @@ fn dyn_type_metadata<'ll, 'tcx>(
fn slice_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
slice_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> MetadataCreationResult<'ll> {
let element_type = match slice_type.kind() {
ty::Slice(element_type) => *element_type,
@ -620,38 +591,11 @@ fn slice_type_metadata<'ll, 'tcx>(
}
pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
// Get the unique type ID of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
// First, try to find the type in `TypeMap`. If we have seen it before, we
// can exit early here.
match type_map.find_metadata_for_type(t) {
Some(metadata) => {
return metadata;
}
None => {
// The Ty is not in the `TypeMap` but maybe we have already seen
// an equivalent type (e.g., only differing in region arguments).
// In order to find out, generate the unique type ID and look
// that up.
let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
match type_map.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => {
// There is already an equivalent type in the TypeMap.
// Register this Ty as an alias in the cache and
// return the cached metadata.
type_map.register_type_with_metadata(t, metadata);
return metadata;
}
None => {
// There really is no type metadata for this type, so
// proceed by creating it.
unique_type_id
}
}
}
}
};
let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t);
if let Some(metadata) = debug_context(cx).type_map.find_metadata_for_unique_id(unique_type_id) {
return metadata;
}
debug!("type_metadata: {:?}", t);
@ -676,64 +620,7 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
ty::Adt(def, _) if def.is_box() => {
pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
}
ty::FnDef(..) | ty::FnPtr(_) => {
if let Some(metadata) =
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
{
return metadata;
}
// It's possible to create a self-referential
// type in Rust by using 'impl trait':
//
// fn foo() -> impl Copy { foo }
//
// See `TypeMap::remove_type` for more detals
// about the workaround.
let temp_type = {
unsafe {
// The choice of type here is pretty arbitrary -
// anything reading the debuginfo for a recursive
// type is going to see *something* weird - the only
// question is what exactly it will see.
let name = "<recur_type>";
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
name.as_ptr().cast(),
name.len(),
cx.size_of(t).bits(),
DW_ATE_unsigned,
)
}
};
let type_map = &debug_context(cx).type_map;
type_map.borrow_mut().register_type_with_metadata(t, temp_type);
let fn_metadata =
subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx)).metadata;
type_map.borrow_mut().remove_type(t);
// This is actually a function pointer, so wrap it in pointer DI.
let (pointer_size, pointer_align) =
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit()));
let name = compute_debuginfo_type_name(cx.tcx, t, false);
let md = unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
fn_metadata,
pointer_size.bits(),
pointer_align.bits() as u32,
0, // Ignore DWARF address space.
name.as_ptr().cast(),
name.len(),
)
};
MetadataCreationResult::new(md, false)
}
ty::FnDef(..) | ty::FnPtr(_) => subroutine_type_metadata(cx, unique_type_id),
ty::Closure(def_id, substs) => {
let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
let containing_scope = get_namespace_for_item(cx, def_id);
@ -764,47 +651,56 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
};
{
let mut type_map = debug_context(cx).type_map.borrow_mut();
if already_stored_in_typemap {
// Also make sure that we already have a `TypeMap` entry for the unique type ID.
let Some(metadata_for_uid) = type_map.find_metadata_for_unique_id(unique_type_id) else {
bug!(
"expected type metadata for unique \
type ID '{}' to already be in \
the `debuginfo::TypeMap` but it \
was not. (Ty = {})",
type_map.get_unique_type_id_as_string(unique_type_id),
t
);
};
match type_map.find_metadata_for_type(t) {
Some(metadata) => {
if metadata != metadata_for_uid {
// Make sure that we really do have a `TypeMap` entry for the unique type ID.
let metadata_for_uid =
match debug_context(cx).type_map.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => metadata,
None => {
bug!(
"mismatch between `Ty` and \
`UniqueTypeId` maps in \
`debuginfo::TypeMap`. \
UniqueTypeId={}, Ty={}",
type_map.get_unique_type_id_as_string(unique_type_id),
t
"expected type metadata for unique \
type ID '{:?}' to already be in \
the `debuginfo::TypeMap` but it \
was not.",
unique_type_id,
);
}
}
None => {
type_map.register_type_with_metadata(t, metadata);
}
}
};
debug_assert_eq!(metadata_for_uid as *const _, metadata as *const _);
} else {
type_map.register_type_with_metadata(t, metadata);
type_map.register_unique_id_with_metadata(unique_type_id, metadata);
debug_context(cx).type_map.register_unique_id_with_metadata(unique_type_id, metadata);
}
}
metadata
}
fn recursion_marker_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType {
*debug_context(cx).recursion_marker_type.get_or_init(move || {
unsafe {
// The choice of type here is pretty arbitrary -
// anything reading the debuginfo for a recursive
// type is going to see *something* weird - the only
// question is what exactly it will see.
//
// FIXME: the name `<recur_type>` does not fit the naming scheme
// of other types.
//
// FIXME: it might make sense to use an actual pointer type here
// so that debuggers can show the address.
let name = "<recur_type>";
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
name.as_ptr().cast(),
name.len(),
cx.tcx.data_layout.pointer_size.bits(),
DW_ATE_unsigned,
)
}
})
}
fn hex_encode(data: &[u8]) -> String {
let mut hex_string = String::with_capacity(data.len() * 2);
for byte in data.iter() {
@ -985,7 +881,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l
fn foreign_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
t: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> &'ll DIType {
debug!("foreign_type_metadata: {:?}", t);
@ -1306,7 +1202,7 @@ fn create_member_descriptions<'ll>(
fn prepare_struct_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
struct_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
@ -1415,7 +1311,7 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
tuple_type: Ty<'tcx>,
component_types: &[Ty<'tcx>],
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
containing_scope: Option<&'ll DIScope>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let (size, align) = cx.size_and_align_of(tuple_type);
@ -1483,7 +1379,7 @@ fn create_member_descriptions<'ll>(
fn prepare_union_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
union_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
@ -1570,7 +1466,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
};
let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() {
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index], index),
ty::Generator(def_id, _, _) => {
let (generator_layout, generator_saved_local_names) =
generator_variant_info_data.as_ref().unwrap();
@ -1913,7 +1809,7 @@ fn create_member_descriptions<'ll>(
#[derive(Copy, Clone)]
enum VariantInfo<'a, 'tcx> {
Adt(&'tcx ty::VariantDef),
Adt(&'tcx ty::VariantDef, VariantIdx),
Generator {
def_id: DefId,
generator_layout: &'tcx GeneratorLayout<'tcx>,
@ -1923,9 +1819,17 @@ enum VariantInfo<'a, 'tcx> {
}
impl<'tcx> VariantInfo<'_, 'tcx> {
fn variant_idx(&self) -> VariantIdx {
match self {
VariantInfo::Adt(_, variant_index) | VariantInfo::Generator { variant_index, .. } => {
*variant_index
}
}
}
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
match self {
VariantInfo::Adt(variant) => f(variant.name.as_str()),
VariantInfo::Adt(variant, _) => f(variant.name.as_str()),
VariantInfo::Generator { variant_index, .. } => {
f(&GeneratorSubsts::variant_name(*variant_index))
}
@ -1934,7 +1838,7 @@ fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
fn variant_name(&self) -> String {
match self {
VariantInfo::Adt(variant) => variant.name.to_string(),
VariantInfo::Adt(variant, _) => variant.name.to_string(),
VariantInfo::Generator { variant_index, .. } => {
// Since GDB currently prints out the raw discriminant along
// with every variant, make each variant name be just the value
@ -1947,7 +1851,7 @@ fn variant_name(&self) -> String {
fn field_name(&self, i: usize) -> String {
let field_name = match *self {
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => {
VariantInfo::Adt(variant, _) if variant.ctor_kind != CtorKind::Fn => {
Some(variant.fields[i].name)
}
VariantInfo::Generator {
@ -1988,10 +1892,8 @@ fn describe_enum_variant<'ll, 'tcx>(
containing_scope: &'ll DIScope,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
let metadata_stub = variant.map_struct_name(|variant_name| {
let unique_type_id = debug_context(cx)
.type_map
.borrow_mut()
.get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name);
let unique_type_id =
UniqueTypeId::for_enum_variant(cx.tcx, layout.ty, variant.variant_idx());
let (size, align) = cx.size_and_align_of(layout.ty);
@ -2021,7 +1923,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
enum_type: Ty<'tcx>,
enum_def_id: DefId,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
outer_field_tys: Vec<Ty<'tcx>>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let tcx = cx.tcx;
@ -2145,8 +2047,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
};
let enum_metadata = {
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
let unique_type_id_str = unique_type_id.generate_unique_id_string(tcx);
unsafe {
llvm::LLVMRustDIBuilderCreateUnionType(
@ -2257,10 +2158,9 @@ fn prepare_enum_metadata<'ll, 'tcx>(
}
};
let variant_part_unique_type_id_str = debug_context(cx)
.type_map
.borrow_mut()
.get_unique_type_id_str_of_enum_variant_part(unique_type_id);
let variant_part_unique_type_id_str =
UniqueTypeId::for_enum_variant_part(tcx, enum_type).generate_unique_id_string(tcx);
let empty_array = create_DIArray(DIB(cx), &[]);
let name = "";
let variant_part = unsafe {
@ -2288,9 +2188,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
// an equivalent layout but offers us much better integration with
// debuggers.
let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
let unique_type_id_str = unique_type_id.generate_unique_id_string(tcx);
unsafe {
llvm::LLVMRustDIBuilderCreateStructType(
@ -2336,7 +2234,7 @@ fn composite_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
composite_type: Ty<'tcx>,
composite_type_name: &str,
composite_type_unique_id: UniqueTypeId,
composite_type_unique_id: UniqueTypeId<'tcx>,
member_descriptions: Vec<MemberDescription<'ll>>,
containing_scope: Option<&'ll DIScope>,
) -> &'ll DICompositeType {
@ -2459,13 +2357,12 @@ fn create_struct_stub<'ll, 'tcx>(
size: Size,
align: Align,
type_name: &str,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
containing_scope: Option<&'ll DIScope>,
flags: DIFlags,
vtable_holder: Option<&'ll DIType>,
) -> &'ll DICompositeType {
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
let unique_type_id = unique_type_id.generate_unique_id_string(cx.tcx);
let metadata_stub = unsafe {
// `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
@ -2499,13 +2396,11 @@ fn create_union_stub<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
union_type: Ty<'tcx>,
union_type_name: &str,
unique_type_id: UniqueTypeId,
unique_type_id: UniqueTypeId<'tcx>,
containing_scope: &'ll DIScope,
) -> &'ll DICompositeType {
let (union_size, union_align) = cx.size_and_align_of(union_type);
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
let unique_type_id = unique_type_id.generate_unique_id_string(cx.tcx);
let metadata_stub = unsafe {
// `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null
@ -2629,10 +2524,7 @@ fn vtable_type_metadata<'ll, 'tcx>(
let vtable_type_name =
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type);
let unique_type_id = debug_context(cx)
.type_map
.borrow_mut()
.get_unique_type_id_of_vtable_type(&vtable_type_name);
let unique_type_id = UniqueTypeId::for_vtable_ty(tcx, ty, poly_trait_ref);
let size = pointer_size * vtable_entries.len() as u64;
// This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate

View file

@ -38,6 +38,7 @@
use smallvec::SmallVec;
use std::cell::RefCell;
use std::iter;
use std::lazy::OnceCell;
use tracing::debug;
mod create_scope_map;
@ -63,9 +64,11 @@ pub struct CrateDebugContext<'a, 'tcx> {
created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
type_map: RefCell<TypeMap<'a, 'tcx>>,
type_map: TypeMap<'a, 'tcx>,
namespace_map: RefCell<DefIdMap<&'a DIScope>>,
recursion_marker_type: OnceCell<&'a DIType>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
@ -93,6 +96,7 @@ pub fn new(llmod: &'a llvm::Module) -> Self {
created_enum_disr_types: Default::default(),
type_map: Default::default(),
namespace_map: RefCell::new(Default::default()),
recursion_marker_type: OnceCell::new(),
composite_types_completed: Default::default(),
}
}

View file

@ -9,10 +9,14 @@
#![feature(crate_visibility_modifier)]
#![feature(let_else)]
#![feature(extern_types)]
#![feature(once_cell)]
#![feature(nll)]
#![recursion_limit = "256"]
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
use back::write::{create_informational_target_machine, create_target_machine};
pub use llvm_util::target_features;

View file

@ -5,7 +5,7 @@
// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}}
//
// CHECK: {{.*}}DISubroutineType{{.*}}
// CHECK: {{.*}}DIBasicType(name: "<recur_type>", encoding: DW_ATE_unsigned)
// CHECK: {{.*}}DIBasicType(name: "<recur_type>", size: {{32|64}}, encoding: DW_ATE_unsigned)
pub fn foo() -> impl Copy {
foo