debuginfo: Generate cross-crate unique type identifiers for debuginfo types.

With this change, rustc creates a unique type identifier for types in debuginfo. These type identifiers are used by LLVM to correctly handle link-time-optimization scenarios but also help rustc with dealing with inlining from other crates. For more information, see the documentation block at the top of librustc/middle/trans/debuginfo.rs.

Fixes #13681.
This commit is contained in:
Michael Woerister
2014-05-30 17:09:16 +02:00
parent c0a6f72e8b
commit 0a98a4e422
3 changed files with 706 additions and 139 deletions
+656 -139
View File
@@ -122,8 +122,36 @@ struct List {
`llvm.dbg.declare` instructions to the correct source locations even while source location emission
is still disabled, so there is no need to do anything special with source location handling here.
*/
## Unique Type Identification
In order for link-time optimization to work properly, LLVM needs a unique type identifier that tells
it across compilation units which types are the same as others. This type identifier is created by
TypeMap::get_unique_type_id_of_type() using the following algorithm:
(1) Primitive types have their name as ID
(2) Structs, enums and traits have a multipart identifier
(1) The first part is the SVH (strict version hash) of the crate they were originally defined in
(2) The second part is the ast::NodeId of the definition in their original crate
(3) The final part is a concatenation of the type IDs of their concrete type arguments if they
are generic types.
(3) Tuple-, pointer and function types are structurally identified, which means that they are
equivalent if their component types are equivalent (i.e. (int, int) is the same regardless in
which crate it is used).
This algorithm also provides a stable ID for types that are defined in one crate but instantiated
from metadata within another crate. We just have to take care to always map crate and node IDs back
to the original crate context.
As a side-effect these unique type IDs also help to solve a problem arising from lifetime
parameters. Since lifetime parameters are completely omitted in debuginfo, more than one `ty::t`
instance may map to the same debuginfo type metadata, that is, some struct `Struct<'a>` may have N
instantiations with different concrete substitutions for `'a`, and thus there will be N `ty::t`
instances for the type `Struct<'a>` even though it is not generic otherwise. Unfortunately this
means that we cannot use `ty::type_id()` as cheap identifier for type metadata---we have done this
in the past, but it led to unnecessary metadata duplication in the best case and LLVM assertions in
the worst. However, the unique type ID as described above *can* be used as identifier. Since it is
comparatively expensive to construct, though, `ty::type_id()` is still used additionally as an
optimization for cases where the exact same type has been seen before (which is most of the time).
*/
use driver::config;
use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
@@ -152,6 +180,7 @@ struct List {
use std::ptr;
use std::rc::{Rc, Weak};
use std::sync::atomics;
use syntax::util::interner::Interner;
use syntax::codemap::{Span, Pos};
use syntax::{abi, ast, codemap, ast_util, ast_map};
use syntax::owned_slice::OwnedSlice;
@@ -166,7 +195,6 @@ struct List {
static DW_ATE_boolean: c_uint = 0x02;
static DW_ATE_float: c_uint = 0x04;
static DW_ATE_signed: c_uint = 0x05;
// static DW_ATE_signed_char: c_uint = 0x06;
static DW_ATE_unsigned: c_uint = 0x07;
static DW_ATE_unsigned_char: c_uint = 0x08;
@@ -174,15 +202,370 @@ struct List {
// Public Interface of debuginfo module
//=-------------------------------------------------------------------------------------------------
#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)]
struct UniqueTypeId(ast::Name);
// 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::t. The
// TypeMap is responsible for creating UniqueTypeIds.
struct TypeMap {
// The UniqueTypeIds created so far
unique_id_interner: Interner<Rc<String>>,
// A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
unique_id_to_metadata: HashMap<UniqueTypeId, DIType>,
// A map from ty::type_id() to debuginfo metadata. This is a N:1 mapping.
type_to_metadata: HashMap<uint, DIType>,
// A map from ty::type_id() to UniqueTypeId. This is a N:1 mapping.
type_to_unique_id: HashMap<uint, UniqueTypeId>
}
impl TypeMap {
fn new() -> TypeMap {
TypeMap {
unique_id_interner: Interner::new(),
type_to_metadata: HashMap::new(),
unique_id_to_metadata: HashMap::new(),
type_to_unique_id: HashMap::new(),
}
}
// Adds a ty::t to metadata mapping to the TypeMap. The method will fail if the mapping already
// exists.
fn register_type_with_metadata(&mut self,
cx: &CrateContext,
type_: ty::t,
metadata: DIType) {
if !self.type_to_metadata.insert(ty::type_id(type_), metadata) {
cx.sess().bug(format!("Type metadata for ty::t '{}' is already in the TypeMap!",
ppaux::ty_to_str(cx.tcx(), type_)).as_slice());
}
}
// 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,
cx: &CrateContext,
unique_type_id: UniqueTypeId,
metadata: DIType) {
if !self.unique_id_to_metadata.insert(unique_type_id, metadata) {
let unique_type_id_str = self.get_unique_type_id_as_string(unique_type_id);
cx.sess().bug(format!("Type metadata for unique id '{}' is already in the TypeMap!",
unique_type_id_str.as_slice()).as_slice());
}
}
fn find_metadata_for_type(&self, type_: ty::t) -> Option<DIType> {
self.type_to_metadata.find_copy(&ty::type_id(type_))
}
fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
self.unique_id_to_metadata.find_copy(&unique_type_id)
}
// Get 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) -> Rc<String> {
let UniqueTypeId(interner_key) = unique_type_id;
self.unique_id_interner.get(interner_key)
}
// Get 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(&mut self, cx: &CrateContext, type_: ty::t) -> UniqueTypeId {
// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T, ..x]) -> {[:size:] :element-uid:}
// vec slice (&[T]) -> {&<mut> [] :element-uid:}
// trait (~ | &[mut] T) -> {:sigil: trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
match self.type_to_unique_id.find_copy(&ty::type_id(type_)) {
Some(unique_type_id) => return unique_type_id,
None => { /* generate one */}
};
let mut unique_type_id = String::with_capacity(256);
unique_type_id.push_char('{');
match ty::get(type_).sty {
ty::ty_nil |
ty::ty_bot |
ty::ty_bool |
ty::ty_char |
ty::ty_str |
ty::ty_int(_) |
ty::ty_uint(_) |
ty::ty_float(_) => {
unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
},
ty::ty_enum(def_id, ref substs) => {
unique_type_id.push_str("enum ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
ty::ty_struct(def_id, ref substs) => {
unique_type_id.push_str("struct ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
ty::ty_tup(ref component_types) => {
unique_type_id.push_str("tuple ");
for &component_type in component_types.iter() {
let component_type_id = self.get_unique_type_id_of_type(cx, component_type);
let component_type_id = self.get_unique_type_id_as_string(component_type_id);
unique_type_id.push_str(component_type_id.as_slice());
}
},
ty::ty_box(inner_type) => {
unique_type_id.push_char('@');
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_uniq(inner_type) => {
unique_type_id.push_char('~');
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
unique_type_id.push_char('*');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
}
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
unique_type_id.push_char('&');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
}
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_vec(ty::mt { ty: inner_type, mutbl }, optional_length) => {
match optional_length {
Some(len) => {
unique_type_id.push_str(format!("[{}]", len).as_slice());
}
None => {
unique_type_id.push_char('&');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
}
unique_type_id.push_str("[]");
}
};
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_trait(ref trait_data) => {
match trait_data.store {
ty::UniqTraitStore => unique_type_id.push_char('~'),
ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut"),
ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_char('&'),
};
unique_type_id.push_str("trait ");
from_def_id_and_substs(self,
cx,
trait_data.def_id,
&trait_data.substs,
&mut unique_type_id);
},
ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
if fn_style == ast::UnsafeFn {
unique_type_id.push_str("unsafe ");
}
unique_type_id.push_str(abi.name());
unique_type_id.push_str(" fn(");
for &parameter_type in sig.inputs.iter() {
let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
unique_type_id.push_str(parameter_type_id.as_slice());
unique_type_id.push_char(',');
}
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str(")->");
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(return_type_id.as_slice());
},
ty::ty_closure(box ty::ClosureTy { fn_style,
onceness,
store,
ref bounds,
ref sig }) => {
if fn_style == ast::UnsafeFn {
unique_type_id.push_str("unsafe ");
}
if onceness == ast::Once {
unique_type_id.push_str("once ");
}
match store {
ty::UniqTraitStore => unique_type_id.push_str("~|"),
ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut|"),
ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_str("&|"),
};
for &parameter_type in sig.inputs.iter() {
let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
unique_type_id.push_str(parameter_type_id.as_slice());
unique_type_id.push_char(',');
}
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str("|->");
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(return_type_id.as_slice());
unique_type_id.push_char(':');
for bound in bounds.iter() {
match bound {
ty::BoundStatic => unique_type_id.push_str("'static"),
ty::BoundSend => unique_type_id.push_str("Send"),
ty::BoundSized => unique_type_id.push_str("Sized"),
ty::BoundCopy => unique_type_id.push_str("Copy"),
ty::BoundShare => unique_type_id.push_str("Share"),
};
unique_type_id.push_char('+');
}
},
_ => {
cx.sess().bug(format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
ppaux::ty_to_str(cx.tcx(), type_).as_slice(),
ty::get(type_).sty).as_slice())
}
};
unique_type_id.push_char('}');
// Trim to size before storing permanently
unique_type_id.shrink_to_fit();
let key = self.unique_id_interner.intern(Rc::new(unique_type_id));
self.type_to_unique_id.insert(ty::type_id(type_), UniqueTypeId(key));
return UniqueTypeId(key);
fn from_def_id_and_substs(type_map: &mut TypeMap,
cx: &CrateContext,
def_id: ast::DefId,
substs: &subst::Substs,
output: &mut String) {
use std::num::ToStrRadix;
// First, find out the 'real' def_id of the type. Items inlined from other crates have
// to be mapped back to their source.
let source_def_id = if def_id.krate == ast::LOCAL_CRATE {
match cx.external_srcs.borrow().find_copy(&def_id.node) {
Some(source_def_id) => {
// The given def_id identifies the inlined copy of a type definition,
// let's take the source of the copy
source_def_id
}
None => def_id
}
} else {
def_id
};
// Get the crate hash as first part of the identifier
let crate_hash = if source_def_id.krate == ast::LOCAL_CRATE {
cx.link_meta.crate_hash.clone()
} else {
cx.sess().cstore.get_crate_hash(source_def_id.krate)
};
output.push_str(crate_hash.as_str());
output.push_str("/");
output.push_str(def_id.node.to_str_radix(16).as_slice());
// Maybe check that there is no self type here
if substs.tps.len() > 0 {
output.push_char('<');
for &type_parameter in substs.tps.iter() {
let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter);
let param_type_id = type_map.get_unique_type_id_as_string(param_type_id);
output.push_str(param_type_id.as_slice());
output.push_char(',');
}
output.push_char('>');
}
}
}
// Get 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(&mut self,
cx: &CrateContext,
enum_type: ty::t,
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)
.as_slice(),
variant_name);
let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
UniqueTypeId(interner_key)
}
}
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext {
llcontext: ContextRef,
builder: DIBuilderRef,
current_debug_location: Cell<DebugLocation>,
created_files: RefCell<HashMap<String, DIFile>>,
created_types: RefCell<HashMap<uint, DIType>>,
created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
type_map: RefCell<TypeMap>,
namespace_map: RefCell<HashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
// This collection is used to assert that composite types (structs, enums, ...) have their
// members only set once:
composite_types_completed: RefCell<HashSet<DIType>>,
@@ -199,8 +582,8 @@ pub fn new(llmod: ModuleRef) -> CrateDebugContext {
builder: builder,
current_debug_location: Cell::new(UnknownLocation),
created_files: RefCell::new(HashMap::new()),
created_types: RefCell::new(HashMap::new()),
created_enum_disr_types: RefCell::new(HashMap::new()),
type_map: RefCell::new(TypeMap::new()),
namespace_map: RefCell::new(HashMap::new()),
composite_types_completed: RefCell::new(HashSet::new()),
};
@@ -1255,7 +1638,8 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
// more information.
enum RecursiveTypeDescription {
UnfinishedMetadata {
cache_id: uint,
unfinished_type: ty::t,
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
file_metadata: DIFile,
@@ -1264,6 +1648,31 @@ enum RecursiveTypeDescription {
FinalMetadata(DICompositeType)
}
fn create_and_register_recursive_type_forward_declaration(
cx: &CrateContext,
unfinished_type: ty::t,
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory)
-> RecursiveTypeDescription {
// 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(cx, unique_type_id, metadata_stub);
type_map.register_type_with_metadata(cx, unfinished_type, metadata_stub);
UnfinishedMetadata {
unfinished_type: unfinished_type,
unique_type_id: unique_type_id,
metadata_stub: metadata_stub,
llvm_type: llvm_type,
file_metadata: file_metadata,
member_description_factory: member_description_factory,
}
}
impl RecursiveTypeDescription {
// Finishes up the description of the type in question (mostly by providing descriptions of the
// fields of the given type) and returns the final type metadata.
@@ -1271,15 +1680,27 @@ fn finalize(&self, cx: &CrateContext) -> DICompositeType {
match *self {
FinalMetadata(metadata) => metadata,
UnfinishedMetadata {
cache_id,
unfinished_type,
unique_type_id,
metadata_stub,
llvm_type,
file_metadata,
ref member_description_factory
} => {
// Insert the stub into the cache in order to allow recursive references ...
debug_context(cx).created_types.borrow_mut()
.insert(cache_id, metadata_stub);
// Make sure that we have a forward declaration of the type in the TypeMap so that
// recursive references are possible. This will always be the case if the
// RecursiveTypeDescription has been properly created through the
// 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() {
cx.sess().bug(format!("Forward declaration of potentially recursive type \
'{}' was not found in TypeMap!",
ppaux::ty_to_str(cx.tcx(), unfinished_type))
.as_slice());
}
}
// ... then create the member descriptions ...
let member_descriptions = member_description_factory.create_member_descriptions(cx);
@@ -1349,6 +1770,7 @@ fn prepare_struct_metadata(cx: &CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
substs: &subst::Substs,
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
@@ -1362,23 +1784,26 @@ fn prepare_struct_metadata(cx: &CrateContext,
let struct_metadata_stub = create_struct_stub(cx,
struct_llvm_type,
struct_name.as_slice(),
unique_type_id,
containing_scope,
file_metadata,
definition_span);
let fields = ty::struct_fields(cx.tcx(), def_id, substs);
UnfinishedMetadata {
cache_id: cache_id_for_type(struct_type),
metadata_stub: struct_metadata_stub,
llvm_type: struct_llvm_type,
file_metadata: file_metadata,
member_description_factory: StructMDF(StructMemberDescriptionFactory {
create_and_register_recursive_type_forward_declaration(
cx,
struct_type,
unique_type_id,
struct_metadata_stub,
struct_llvm_type,
file_metadata,
StructMDF(StructMemberDescriptionFactory {
fields: fields,
is_simd: ty::type_is_simd(cx.tcx(), struct_type),
span: span,
}),
}
})
)
}
@@ -1409,6 +1834,7 @@ fn create_member_descriptions(&self, cx: &CrateContext)
fn prepare_tuple_metadata(cx: &CrateContext,
tuple_type: ty::t,
component_types: &[ty::t],
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
@@ -1417,21 +1843,24 @@ fn prepare_tuple_metadata(cx: &CrateContext,
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
UnfinishedMetadata {
cache_id: cache_id_for_type(tuple_type),
metadata_stub: create_struct_stub(cx,
tuple_llvm_type,
tuple_name.as_slice(),
file_metadata,
file_metadata,
span),
llvm_type: tuple_llvm_type,
file_metadata: file_metadata,
member_description_factory: TupleMDF(TupleMemberDescriptionFactory {
create_and_register_recursive_type_forward_declaration(
cx,
tuple_type,
unique_type_id,
create_struct_stub(cx,
tuple_llvm_type,
tuple_name.as_slice(),
unique_type_id,
file_metadata,
file_metadata,
span),
tuple_llvm_type,
file_metadata,
TupleMDF(TupleMemberDescriptionFactory {
component_types: Vec::from_slice(component_types),
span: span,
})
}
)
}
@@ -1444,6 +1873,7 @@ fn prepare_tuple_metadata(cx: &CrateContext,
// variant of the given enum, this factory will produce one MemberDescription (all with no name and
// a fixed offset of zero bytes).
struct EnumMemberDescriptionFactory {
enum_type: ty::t,
type_rep: Rc<adt::Repr>,
variants: Rc<Vec<Rc<ty::VariantInfo>>>,
discriminant_type_metadata: Option<DIType>,
@@ -1465,6 +1895,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
.map(|(i, struct_def)| {
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
describe_enum_variant(cx,
self.enum_type,
struct_def,
&**self.variants.get(i),
discriminant_info,
@@ -1497,6 +1928,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
} else {
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
self.enum_type,
struct_def,
&**self.variants.get(0),
NoDiscriminant,
@@ -1551,11 +1983,19 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
offset: FixedMemberOffset { bytes: 0 },
};
let unique_type_id = debug_context(cx).type_map
.borrow_mut()
.get_unique_type_id_of_enum_variant(
cx,
self.enum_type,
non_null_variant_name.get());
// Now we can create the metadata of the artificial struct
let artificial_struct_metadata =
composite_type_metadata(cx,
artificial_struct_llvm_type,
non_null_variant_name.get(),
unique_type_id,
&[sole_struct_member_description],
self.containing_scope,
self.file_metadata,
@@ -1581,6 +2021,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
// Create a description of the non-null variant
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
self.enum_type,
struct_def,
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
@@ -1654,6 +2095,7 @@ enum EnumDiscriminantInfo {
// (3) a MemberDescriptionFactory for producing the descriptions of the fields of the variant. This
// is a rudimentary version of a full RecursiveTypeDescription.
fn describe_enum_variant(cx: &CrateContext,
enum_type: ty::t,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_info: EnumDiscriminantInfo,
@@ -1678,9 +2120,19 @@ fn describe_enum_variant(cx: &CrateContext,
codemap::DUMMY_SP
};
let variant_name = token::get_ident(variant_info.name);
let variant_name = variant_name.get();
let unique_type_id = debug_context(cx).type_map
.borrow_mut()
.get_unique_type_id_of_enum_variant(
cx,
enum_type,
variant_name);
let metadata_stub = create_struct_stub(cx,
variant_llvm_type,
token::get_ident(variant_info.name).get(),
variant_name,
unique_type_id,
containing_scope,
file_metadata,
variant_definition_span);
@@ -1724,6 +2176,7 @@ fn describe_enum_variant(cx: &CrateContext,
fn prepare_enum_metadata(cx: &CrateContext,
enum_type: ty::t,
enum_def_id: ast::DefId,
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
@@ -1804,10 +2257,14 @@ fn prepare_enum_metadata(cx: &CrateContext,
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
let unique_id = generate_unique_type_id("DI_ENUM_");
let unique_type_id_str = debug_context(cx)
.type_map
.borrow()
.get_unique_type_id_as_string(unique_type_id);
let enum_metadata = enum_name.as_slice().with_c_str(|enum_name| {
unique_id.as_slice().with_c_str(|unique_id| {
unique_type_id_str.as_slice().with_c_str(|unique_type_id_str| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
@@ -1820,17 +2277,20 @@ fn prepare_enum_metadata(cx: &CrateContext,
0, // Flags
ptr::null(),
0, // RuntimeLang
unique_id)
unique_type_id_str)
}
})
});
return UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: enum_metadata,
llvm_type: enum_llvm_type,
file_metadata: file_metadata,
member_description_factory: EnumMDF(EnumMemberDescriptionFactory {
return create_and_register_recursive_type_forward_declaration(
cx,
enum_type,
unique_type_id,
enum_metadata,
enum_llvm_type,
file_metadata,
EnumMDF(EnumMemberDescriptionFactory {
enum_type: enum_type,
type_rep: type_rep.clone(),
variants: variants,
discriminant_type_metadata: discriminant_type_metadata,
@@ -1838,7 +2298,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
file_metadata: file_metadata,
span: span,
}),
};
);
fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
let name = if def_id.krate == ast::LOCAL_CRATE {
@@ -1857,6 +2317,7 @@ fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::I
fn composite_type_metadata(cx: &CrateContext,
composite_llvm_type: Type,
composite_type_name: &str,
composite_type_unique_id: UniqueTypeId,
member_descriptions: &[MemberDescription],
containing_scope: DIScope,
file_metadata: DIFile,
@@ -1866,10 +2327,10 @@ fn composite_type_metadata(cx: &CrateContext,
let composite_type_metadata = create_struct_stub(cx,
composite_llvm_type,
composite_type_name,
composite_type_unique_id,
containing_scope,
file_metadata,
definition_span);
// ... and immediately create and add the member descriptions.
set_members_of_composite_type(cx,
composite_type_metadata,
@@ -1944,6 +2405,7 @@ fn set_members_of_composite_type(cx: &CrateContext,
fn create_struct_stub(cx: &CrateContext,
struct_llvm_type: Type,
struct_type_name: &str,
unique_type_id: UniqueTypeId,
containing_scope: DIScope,
file_metadata: DIFile,
definition_span: Span)
@@ -1951,13 +2413,12 @@ fn create_struct_stub(cx: &CrateContext,
let loc = span_start(cx, definition_span);
let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
// We assign unique IDs to the type stubs so LLVM metadata uniquing does not reuse instances
// where we don't want it.
let unique_id = generate_unique_type_id("DI_STRUCT_");
return unsafe {
let unique_type_id_str = debug_context(cx).type_map
.borrow()
.get_unique_type_id_as_string(unique_type_id);
let metadata_stub = unsafe {
struct_type_name.with_c_str(|name| {
unique_id.as_slice().with_c_str(|unique_id| {
unique_type_id_str.as_slice().with_c_str(|unique_type_id| {
// LLVMDIBuilderCreateStructType() wants an empty array. A null pointer will lead to
// hard to trace and debug LLVM assertions later on in llvm/lib/IR/Value.cpp
let empty_array = create_DIArray(DIB(cx), []);
@@ -1975,23 +2436,23 @@ fn create_struct_stub(cx: &CrateContext,
empty_array,
0,
ptr::null(),
unique_id)
unique_type_id)
})
})
};
return metadata_stub;
}
fn boxed_type_metadata(cx: &CrateContext,
content_type_name: Option<&str>,
content_llvm_type: Type,
content_type_metadata: DIType,
span: Span)
-> DICompositeType {
let box_type_name = match content_type_name {
Some(content_type_name) => format!("Boxed<{}>", content_type_name),
None => "BoxedType".to_string()
};
fn at_box_metadata(cx: &CrateContext,
content_type: ty::t,
unique_type_id: UniqueTypeId) -> DIType {
let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
let content_type_name = content_type_name.as_slice();
let content_llvm_type = type_of::type_of(cx, content_type);
let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
let box_type_name = format!("Boxed<{}>", content_type_name);
let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
assert!(box_layout_is_correct(cx,
@@ -2035,17 +2496,18 @@ fn boxed_type_metadata(cx: &CrateContext,
}
];
let loc = span_start(cx, span);
let loc = span_start(cx, codemap::DUMMY_SP);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
return composite_type_metadata(
cx,
box_llvm_type,
box_type_name.as_slice(),
unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
span);
codemap::DUMMY_SP);
// Unfortunately, we cannot assert anything but the correct types here---and not whether the
// 'next' and 'prev' pointers are in the correct order.
@@ -2062,6 +2524,7 @@ fn box_layout_is_correct(cx: &CrateContext,
}
}
fn fixed_vec_metadata(cx: &CrateContext,
element_type: ty::t,
len: uint,
@@ -2089,18 +2552,19 @@ fn fixed_vec_metadata(cx: &CrateContext,
};
}
fn vec_metadata(cx: &CrateContext,
element_type: ty::t,
span: Span)
-> DICompositeType {
fn heap_vec_metadata(cx: &CrateContext,
vec_type: ty::t,
element_type: ty::t,
unique_type_id: UniqueTypeId,
span: Span)
-> DICompositeType {
let element_type_metadata = type_metadata(cx, element_type, span);
let element_llvm_type = type_of::type_of(cx, element_type);
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
let vec_llvm_type = Type::vec(cx, &element_llvm_type);
let vec_type_name = format!("[{}]",
ppaux::ty_to_str(cx.tcx(), element_type));
let vec_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
let vec_type_name = vec_type_name.as_slice();
let member_llvm_types = vec_llvm_type.field_types();
@@ -2145,6 +2609,7 @@ fn vec_metadata(cx: &CrateContext,
cx,
vec_llvm_type,
vec_type_name,
unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
@@ -2154,6 +2619,7 @@ fn vec_metadata(cx: &CrateContext,
fn vec_slice_metadata(cx: &CrateContext,
vec_type: ty::t,
element_type: ty::t,
unique_type_id: UniqueTypeId,
span: Span)
-> DICompositeType {
@@ -2196,6 +2662,7 @@ fn vec_slice_metadata(cx: &CrateContext,
cx,
slice_llvm_type,
slice_type_name.as_slice(),
unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
@@ -2218,8 +2685,7 @@ fn subroutine_type_metadata(cx: &CrateContext,
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
let mut signature_metadata: Vec<DIType> =
Vec::with_capacity(signature.inputs.len() + 1);
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
// return type
signature_metadata.push(match ty::get(signature.output).sty {
@@ -2245,7 +2711,8 @@ fn trait_metadata(cx: &CrateContext,
trait_type: ty::t,
substs: &subst::Substs,
trait_store: ty::TraitStore,
_: &ty::BuiltinBounds)
_: &ty::BuiltinBounds,
unique_type_id: UniqueTypeId)
-> DIType {
// The implementation provided here is a stub. It makes sure that the trait type is
// assigned the correct name, size, namespace, and source location. But it does not describe
@@ -2272,49 +2739,55 @@ fn trait_metadata(cx: &CrateContext,
composite_type_metadata(cx,
trait_llvm_type,
name.as_slice(),
unique_type_id,
[],
containing_scope,
file_metadata,
definition_span)
}
fn type_metadata(cx: &CrateContext,
t: ty::t,
usage_site_span: Span)
-> DIType {
let cache_id = cache_id_for_type(t);
match debug_context(cx).created_types.borrow().find(&cache_id) {
Some(type_metadata) => return *type_metadata,
None => ()
}
fn create_pointer_to_box_metadata(cx: &CrateContext,
pointer_type: ty::t,
type_in_box: ty::t)
-> DIType {
let content_type_name = ppaux::ty_to_str(cx.tcx(), type_in_box);
let content_type_name = content_type_name.as_slice();
let content_llvm_type = type_of::type_of(cx, type_in_box);
let content_type_metadata = type_metadata(
cx,
type_in_box,
codemap::DUMMY_SP);
let box_metadata = boxed_type_metadata(
cx,
Some(content_type_name),
content_llvm_type,
content_type_metadata,
codemap::DUMMY_SP);
pointer_type_metadata(cx, pointer_type, box_metadata)
}
// Get the unique type id of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
match type_map.find_metadata_for_type(t) {
Some(metadata) => {
return metadata;
},
None => {
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) => {
type_map.register_type_with_metadata(cx, t, metadata);
return metadata;
},
None => {
// There really is no type metadata for this type, so proceed by creating
// it
unique_type_id
}
}
}
}
};
debug!("type_metadata: {:?}", ty::get(t));
macro_rules! return_if_created_in_meantime(
() => (
match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => return metadata,
None => { /* proceed normally */ }
};
)
)
let sty = &ty::get(t).sty;
let type_metadata = match *sty {
let (type_metadata, should_already_be_stored_in_typemap) = match *sty {
ty::ty_nil |
ty::ty_bot |
ty::ty_bool |
@@ -2322,50 +2795,73 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
ty::ty_int(_) |
ty::ty_uint(_) |
ty::ty_float(_) => {
basic_type_metadata(cx, t)
(basic_type_metadata(cx, t), false)
}
ty::ty_enum(def_id, _) => {
prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
let is_c_style_enum = match *adt::represent_type(cx, t) {
adt::CEnum(..) => true,
_ => false
};
(prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx),
!is_c_style_enum)
}
ty::ty_box(typ) => {
create_pointer_to_box_metadata(cx, t, typ)
ty::ty_box(pointee_type) => {
let box_content_metadata = at_box_metadata(cx, pointee_type, unique_type_id);
return_if_created_in_meantime!();
(pointer_type_metadata(cx, t, box_content_metadata), false)
}
ty::ty_vec(ref mt, Some(len)) => fixed_vec_metadata(cx, mt.ty, len, usage_site_span),
ty::ty_uniq(typ) => {
match ty::get(typ).sty {
ty::ty_vec(ref mt, Some(len)) => {
(fixed_vec_metadata(cx, mt.ty, len, usage_site_span), false)
}
ty::ty_uniq(pointee_type) => {
(match ty::get(pointee_type).sty {
ty::ty_vec(ref mt, None) => {
let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
let vec_metadata = heap_vec_metadata(cx,
pointee_type,
mt.ty,
unique_type_id,
usage_site_span);
return_if_created_in_meantime!();
pointer_type_metadata(cx, t, vec_metadata)
}
ty::ty_str => {
let i8_t = ty::mk_i8();
let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
let vec_metadata = heap_vec_metadata(cx,
pointee_type,
i8_t,
unique_type_id,
usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
_ => {
let pointee = type_metadata(cx, typ, usage_site_span);
pointer_type_metadata(cx, t, pointee)
let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
return_if_created_in_meantime!();
pointer_type_metadata(cx, t, pointee_metadata)
}
}
}, false)
}
ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
match ty::get(mt.ty).sty {
ty::ty_vec(ref mt, None) => vec_slice_metadata(cx, t, mt.ty, usage_site_span),
(match ty::get(mt.ty).sty {
ty::ty_vec(ref mt, None) => {
vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
}
ty::ty_str => {
let i8_t = ty::mk_i8();
vec_slice_metadata(cx, t, i8_t, usage_site_span)
vec_slice_metadata(cx, t, i8_t, unique_type_id, usage_site_span)
}
_ => {
let pointee = type_metadata(cx, mt.ty, usage_site_span);
return_if_created_in_meantime!();
pointer_type_metadata(cx, t, pointee)
}
}
}, false)
}
ty::ty_bare_fn(ref barefnty) => {
subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
(subroutine_type_metadata(cx, &barefnty.sig, usage_site_span), false)
}
ty::ty_closure(ref closurety) => {
subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
(subroutine_type_metadata(cx, &closurety.sig, usage_site_span), false)
}
ty::ty_trait(box ty::TyTrait {
def_id,
@@ -2373,25 +2869,60 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
store,
ref bounds
}) => {
trait_metadata(cx, def_id, t, substs, store, bounds)
(trait_metadata(cx, def_id, t, substs, store, bounds, unique_type_id), false)
}
ty::ty_struct(def_id, ref substs) => {
prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
let struct_metadata = prepare_struct_metadata(cx,
t,
def_id,
substs,
unique_type_id,
usage_site_span).finalize(cx);
(struct_metadata, true)
}
ty::ty_tup(ref elements) => {
prepare_tuple_metadata(cx,
t,
elements.as_slice(),
usage_site_span).finalize(cx)
let tuple_metadata = prepare_tuple_metadata(cx,
t,
elements.as_slice(),
unique_type_id,
usage_site_span).finalize(cx);
(tuple_metadata, true)
}
_ => {
cx.sess().bug(format!("debuginfo: unexpected type in \
type_metadata: {:?}",
cx.sess().bug(format!("debuginfo: unexpected type in type_metadata: {:?}",
sty).as_slice())
}
};
debug_context(cx).created_types.borrow_mut().insert(cache_id, type_metadata);
{
let mut type_map = debug_context(cx).type_map.borrow_mut();
if should_already_be_stored_in_typemap {
// Make sure that we already have a TypeMap entry entry for the ty::t.
if type_map.find_metadata_for_type(t).is_none() {
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
let error_message = format!("Expected type metadata for ty::t '{}' to already be in
the TypeMap but it was not (unique type id = {})",
ppaux::ty_to_str(cx.tcx(), t),
unique_type_id_str.as_slice());
cx.sess().span_bug(usage_site_span, error_message.as_slice());
}
// Also make sure that we already have a TypeMap entry entry for the unique type id.
if type_map.find_metadata_for_unique_id(unique_type_id).is_none() {
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
let error_message = format!("Expected type metadata for unique type id '{}' to
already be in the TypeMap but it was not. (ty::t = {})",
unique_type_id_str.as_slice(),
ppaux::ty_to_str(cx.tcx(), t));
cx.sess().span_bug(usage_site_span, error_message.as_slice());
}
} else {
type_map.register_type_with_metadata(cx, t, type_metadata);
type_map.register_unique_id_with_metadata(cx, unique_type_id, type_metadata);
}
}
type_metadata
}
@@ -2446,20 +2977,6 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
// Utility Functions
//=-------------------------------------------------------------------------------------------------
fn cache_id_for_type(t: ty::t) -> uint {
ty::type_id(t)
}
// Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and
// `prepare_enum_metadata()`.
fn generate_unique_type_id(prefix: &'static str) -> String {
unsafe {
static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
format!("{}{}", prefix,
unique_id_counter.fetch_add(1, atomics::SeqCst))
}
}
/// Return codemap::Loc corresponding to the beginning of the span
fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
cx.sess().codemap().lookup_char_pos(span.lo)
@@ -0,0 +1,26 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![crate_type = "rlib"]
// compile-flags:-g
struct S1;
impl S1 {
fn f(&mut self) { }
}
struct S2;
impl S2 {
fn f(&mut self) { }
}
@@ -0,0 +1,24 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-android: FIXME(#10381)
// aux-build:cross_crate_debuginfo_type_uniquing.rs
extern crate cross_crate_debuginfo_type_uniquing;
// no-prefer-dynamic
// compile-flags:-g -Zlto
pub struct C;
pub fn p() -> C {
C
}
fn main() { }