use lib::llvm::llvm;
use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
+use metadata::csearch;
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::datum::{Datum, Lvalue};
use std::cell::{Cell, RefCell};
use collections::HashMap;
use collections::HashSet;
-use std::libc::{c_uint, c_ulonglong, c_longlong};
+use libc::{c_uint, c_ulonglong, c_longlong};
use std::ptr;
+use std::strbuf::StrBuf;
use std::sync::atomics;
-use std::slice;
use syntax::codemap::{Span, Pos};
use syntax::{abi, ast, codemap, ast_util, ast_map};
use syntax::owned_slice::OwnedSlice;
current_debug_location: Cell<DebugLocation>,
created_files: RefCell<HashMap<~str, DIFile>>,
created_types: RefCell<HashMap<uint, DIType>>,
+ created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
namespace_map: RefCell<HashMap<Vec<ast::Name> , @NamespaceTreeNode>>,
// This collection is used to assert that composite types (structs, enums, ...) have their
// members only set once:
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()),
namespace_map: RefCell::new(HashMap::new()),
composite_types_completed: RefCell::new(HashSet::new()),
};
}
}
-pub enum FunctionDebugContext {
- priv FunctionDebugContext(~FunctionDebugContextData),
- priv DebugInfoDisabled,
- priv FunctionWithoutDebugInfo,
+pub struct FunctionDebugContext {
+ repr: FunctionDebugContextRepr,
+}
+
+enum FunctionDebugContextRepr {
+ FunctionDebugContext(~FunctionDebugContextData),
+ DebugInfoDisabled,
+ FunctionWithoutDebugInfo,
}
impl FunctionDebugContext {
fn get_ref<'a>(&'a self, cx: &CrateContext, span: Span) -> &'a FunctionDebugContextData {
- match *self {
+ match self.repr {
FunctionDebugContext(~ref data) => data,
DebugInfoDisabled => {
cx.sess().span_bug(span, FunctionDebugContext::debuginfo_disabled_message());
return;
}
+ // Don't create debuginfo for globals inlined from other crates. The other crate should already
+ // contain debuginfo for it. More importantly, the global might not even exist in un-inlined
+ // form anywhere which would lead to a linker errors.
+ if cx.external_srcs.borrow().contains_key(&node_id) {
+ return;
+ }
+
let var_item = cx.tcx.map.get(node_id);
let (ident, span) = match var_item {
env_data_type: ty::t,
env_pointer: ValueRef,
env_index: uint,
- closure_sigil: ast::Sigil,
+ closure_store: ty::TraitStore,
span: Span) {
if fn_should_be_ignored(bcx.fcx) {
return;
llvm::LLVMDIBuilderCreateOpDeref(Type::i64(cx).to_ref())]
};
- let address_op_count = match closure_sigil {
- ast::BorrowedSigil => {
+ let address_op_count = match closure_store {
+ ty::RegionTraitStore(..) => {
address_operations.len()
}
- ast::ManagedSigil | ast::OwnedSigil => {
+ ty::UniqTraitStore => {
address_operations.len() - 1
}
};
pub fn set_source_location(fcx: &FunctionContext,
node_id: ast::NodeId,
span: Span) {
- if fn_should_be_ignored(fcx) {
- return;
- }
-
- let cx = fcx.ccx;
+ match fcx.debug_context.repr {
+ DebugInfoDisabled => return,
+ FunctionWithoutDebugInfo => {
+ set_debug_location(fcx.ccx, UnknownLocation);
+ return;
+ }
+ FunctionDebugContext(~ref function_debug_context) => {
+ let cx = fcx.ccx;
- debug!("set_source_location: {}", cx.sess().codemap().span_to_str(span));
+ debug!("set_source_location: {}", cx.sess().codemap().span_to_str(span));
- if fcx.debug_context.get_ref(cx, span).source_locations_enabled.get() {
- let loc = span_start(cx, span);
- let scope = scope_metadata(fcx, node_id, span);
+ if function_debug_context.source_locations_enabled.get() {
+ let loc = span_start(cx, span);
+ let scope = scope_metadata(fcx, node_id, span);
- set_debug_location(cx, DebugLocation::new(scope, loc.line, loc.col.to_uint()));
- } else {
- set_debug_location(cx, UnknownLocation);
+ set_debug_location(cx, DebugLocation::new(scope, loc.line, loc.col.to_uint()));
+ } else {
+ set_debug_location(cx, UnknownLocation);
+ }
+ }
}
}
/// and must therefore be called before the first real statement/expression of the function is
/// translated.
pub fn start_emitting_source_locations(fcx: &FunctionContext) {
- match fcx.debug_context {
+ match fcx.debug_context.repr {
FunctionDebugContext(~ref data) => {
data.source_locations_enabled.set(true)
},
param_substs: Option<@param_substs>,
llfn: ValueRef) -> FunctionDebugContext {
if cx.sess().opts.debuginfo == NoDebugInfo {
- return DebugInfoDisabled;
+ return FunctionDebugContext { repr: DebugInfoDisabled };
}
+ // Clear the debug location so we don't assign them in the function prelude. Do this here
+ // already, in case we do an early exit from this function.
+ set_debug_location(cx, UnknownLocation);
+
if fn_ast_id == -1 {
- return FunctionWithoutDebugInfo;
+ return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
}
let empty_generics = ast::Generics { lifetimes: Vec::new(), ty_params: OwnedSlice::empty() };
ast_map::NodeForeignItem(..) |
ast_map::NodeVariant(..) |
ast_map::NodeStructCtor(..) => {
- return FunctionWithoutDebugInfo;
+ return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
}
_ => cx.sess().bug(format!("create_function_debug_context: \
unexpected sort of node: {:?}", fnitem))
// This can be the case for functions inlined from another crate
if span == codemap::DUMMY_SP {
- return FunctionWithoutDebugInfo;
+ return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
}
let loc = span_start(cx, span);
};
// get_template_parameters() will append a `<...>` clause to the function name if necessary.
- let mut function_name = token::get_ident(ident).get().to_str();
+ let mut function_name = StrBuf::from_str(token::get_ident(ident).get());
let template_parameters = get_template_parameters(cx,
generics,
param_substs,
// ast_map, or construct a path using the enclosing function).
let (linkage_name, containing_scope) = if has_path {
let namespace_node = namespace_for_item(cx, ast_util::local_def(fn_ast_id));
- let linkage_name = namespace_node.mangled_name_of_contained_item(function_name);
+ let linkage_name = namespace_node.mangled_name_of_contained_item(
+ function_name.as_slice());
let containing_scope = namespace_node.scope;
(linkage_name, containing_scope)
} else {
- (function_name.clone(), file_metadata)
+ (function_name.as_slice().to_owned(), file_metadata)
};
// Clang sets this parameter to the opening brace of the function's block, so let's do this too.
let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
- let fn_metadata = function_name.with_c_str(|function_name| {
+ let fn_metadata = function_name.as_slice().with_c_str(|function_name| {
linkage_name.with_c_str(|linkage_name| {
unsafe {
llvm::LLVMDIBuilderCreateFunction(
fn_metadata,
&mut *fn_debug_context.scope_map.borrow_mut());
- // Clear the debug location so we don't assign them in the function prelude
- set_debug_location(cx, UnknownLocation);
-
- return FunctionDebugContext(fn_debug_context);
+ return FunctionDebugContext { repr: FunctionDebugContext(fn_debug_context) };
fn get_function_signature(cx: &CrateContext,
fn_ast_id: ast::NodeId,
return create_DIArray(DIB(cx), []);
}
- let mut signature = slice::with_capacity(fn_decl.inputs.len() + 1);
+ let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1);
// Return type -- llvm::DIBuilder wants this at index 0
match fn_decl.output.node {
signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP));
}
- return create_DIArray(DIB(cx), signature);
+ return create_DIArray(DIB(cx), signature.as_slice());
}
fn get_template_parameters(cx: &CrateContext,
generics: &ast::Generics,
param_substs: Option<@param_substs>,
file_metadata: DIFile,
- name_to_append_suffix_to: &mut ~str)
- -> DIArray {
+ name_to_append_suffix_to: &mut StrBuf)
+ -> DIArray {
let self_type = match param_substs {
Some(param_substs) => param_substs.self_ty,
_ => None
// prepend "./" if necessary
let dotdot = bytes!("..");
let prefix = &[dotdot[0], ::std::path::SEP_BYTE];
- let mut path_bytes = p.as_vec().to_owned();
+ let mut path_bytes = Vec::from_slice(p.as_vec());
if path_bytes.slice_to(2) != prefix &&
path_bytes.slice_to(2) != dotdot {
path_bytes.insert(1, prefix[1]);
}
- path_bytes.to_c_str()
+ path_bytes.as_slice().to_c_str()
}
_ => fallback_path(cx)
}
debug!("basic_type_metadata: {:?}", ty::get(t));
let (name, encoding) = match ty::get(t).sty {
- ty::ty_nil => (~"()", DW_ATE_unsigned),
- ty::ty_bot => (~"!", DW_ATE_unsigned),
- ty::ty_bool => (~"bool", DW_ATE_boolean),
- ty::ty_char => (~"char", DW_ATE_unsigned_char),
+ ty::ty_nil => ("()".to_owned(), DW_ATE_unsigned),
+ ty::ty_bot => ("!".to_owned(), DW_ATE_unsigned),
+ ty::ty_bool => ("bool".to_owned(), DW_ATE_boolean),
+ ty::ty_char => ("char".to_owned(), DW_ATE_unsigned_char),
ty::ty_int(int_ty) => match int_ty {
- ast::TyI => (~"int", DW_ATE_signed),
- ast::TyI8 => (~"i8", DW_ATE_signed),
- ast::TyI16 => (~"i16", DW_ATE_signed),
- ast::TyI32 => (~"i32", DW_ATE_signed),
- ast::TyI64 => (~"i64", DW_ATE_signed)
+ ast::TyI => ("int".to_owned(), DW_ATE_signed),
+ ast::TyI8 => ("i8".to_owned(), DW_ATE_signed),
+ ast::TyI16 => ("i16".to_owned(), DW_ATE_signed),
+ ast::TyI32 => ("i32".to_owned(), DW_ATE_signed),
+ ast::TyI64 => ("i64".to_owned(), DW_ATE_signed)
},
ty::ty_uint(uint_ty) => match uint_ty {
- ast::TyU => (~"uint", DW_ATE_unsigned),
- ast::TyU8 => (~"u8", DW_ATE_unsigned),
- ast::TyU16 => (~"u16", DW_ATE_unsigned),
- ast::TyU32 => (~"u32", DW_ATE_unsigned),
- ast::TyU64 => (~"u64", DW_ATE_unsigned)
+ ast::TyU => ("uint".to_owned(), DW_ATE_unsigned),
+ ast::TyU8 => ("u8".to_owned(), DW_ATE_unsigned),
+ ast::TyU16 => ("u16".to_owned(), DW_ATE_unsigned),
+ ast::TyU32 => ("u32".to_owned(), DW_ATE_unsigned),
+ ast::TyU64 => ("u64".to_owned(), DW_ATE_unsigned)
},
ty::ty_float(float_ty) => match float_ty {
- ast::TyF32 => (~"f32", DW_ATE_float),
- ast::TyF64 => (~"f64", DW_ATE_float)
+ ast::TyF32 => ("f32".to_owned(), DW_ATE_float),
+ ast::TyF64 => ("f64".to_owned(), DW_ATE_float)
},
_ => cx.sess().bug("debuginfo::basic_type_metadata - t is invalid type")
};
-> Vec<MemberDescription> {
self.fields.iter().map(|field| {
let name = if field.ident.name == special_idents::unnamed_field.name {
- ~""
+ "".to_owned()
} else {
token::get_ident(field.ident).get().to_str()
};
-> Vec<MemberDescription> {
self.component_types.iter().map(|&component_type| {
MemberDescription {
- name: ~"",
+ name: "".to_owned(),
llvm_type: type_of::type_of(cx, component_type),
type_metadata: type_metadata(cx, component_type, self.span),
offset: ComputedMemberOffset,
self.file_metadata,
codemap::DUMMY_SP);
MemberDescription {
- name: ~"",
+ name: "".to_owned(),
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
Some(ref names) => {
names.iter().map(|ident| token::get_ident(*ident).get().to_str()).collect()
}
- None => variant_info.args.iter().map(|_| ~"").collect()
+ None => variant_info.args.iter().map(|_| "".to_owned()).collect()
};
// If this is not a univariant enum, there is also the (unnamed) discriminant field
if discriminant_type_metadata.is_some() {
- arg_names.insert(0, ~"");
+ arg_names.insert(0, "".to_owned());
}
// Build an array of (field name, field type) pairs to be captured in the factory closure.
.collect();
let discriminant_type_metadata = |inttype| {
- let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
- let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
- let discriminant_base_type_metadata = type_metadata(cx, adt::ty_of_inttype(inttype),
- codemap::DUMMY_SP);
- enum_name.with_c_str(|enum_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerationType(
- DIB(cx),
- containing_scope,
- enum_name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(discriminant_size),
- bytes_to_bits(discriminant_align),
- create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
- discriminant_base_type_metadata)
+ // We can reuse the type of the discriminant for all monomorphized instances of an enum
+ // because it doesn't depend on any type parameters. The def_id, uniquely identifying the
+ // enum's polytype acts as key in this cache.
+ let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
+ .borrow()
+ .find_copy(&enum_def_id);
+ match cached_discriminant_type_metadata {
+ Some(discriminant_type_metadata) => discriminant_type_metadata,
+ None => {
+ let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
+ let (discriminant_size, discriminant_align) =
+ size_and_align_of(cx, discriminant_llvm_type);
+ let discriminant_base_type_metadata = type_metadata(cx,
+ adt::ty_of_inttype(inttype),
+ codemap::DUMMY_SP);
+ let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
+
+ let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateEnumerationType(
+ DIB(cx),
+ containing_scope,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(discriminant_size),
+ bytes_to_bits(discriminant_align),
+ create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
+ discriminant_base_type_metadata)
+ }
+ });
+
+ debug_context(cx).created_enum_disr_types
+ .borrow_mut()
+ .insert(enum_def_id, discriminant_type_metadata);
+
+ discriminant_type_metadata
}
- })
+ }
};
let type_rep = adt::represent_type(cx, enum_type);
}
}
};
+
+ fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
+ let name = if def_id.krate == ast::LOCAL_CRATE {
+ cx.tcx.map.get_path_elem(def_id.node).name()
+ } else {
+ csearch::get_item_path(&cx.tcx, def_id).last().unwrap().name()
+ };
+
+ token::get_name(name)
+ }
}
enum MemberOffset {
-> DICompositeType {
let box_type_name = match content_type_name {
Some(content_type_name) => format!("Boxed<{}>", content_type_name),
- None => ~"BoxedType"
+ None => "BoxedType".to_owned()
};
let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_descriptions = [
MemberDescription {
- name: ~"refcnt",
+ name: "refcnt".to_owned(),
llvm_type: *member_llvm_types.get(0),
type_metadata: type_metadata(cx, int_type, codemap::DUMMY_SP),
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"drop_glue",
+ name: "drop_glue".to_owned(),
llvm_type: *member_llvm_types.get(1),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"prev",
+ name: "prev".to_owned(),
llvm_type: *member_llvm_types.get(2),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"next",
+ name: "next".to_owned(),
llvm_type: *member_llvm_types.get(3),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"val",
+ name: "val".to_owned(),
llvm_type: *member_llvm_types.get(4),
type_metadata: content_type_metadata,
offset: ComputedMemberOffset,
let member_descriptions = [
MemberDescription {
- name: ~"fill",
+ name: "fill".to_owned(),
llvm_type: *member_llvm_types.get(0),
type_metadata: int_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"alloc",
+ name: "alloc".to_owned(),
llvm_type: *member_llvm_types.get(1),
type_metadata: int_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"elements",
+ name: "elements".to_owned(),
llvm_type: *member_llvm_types.get(2),
type_metadata: array_type_metadata,
offset: ComputedMemberOffset,
let member_descriptions = [
MemberDescription {
- name: ~"data_ptr",
+ name: "data_ptr".to_owned(),
llvm_type: *member_llvm_types.get(0),
type_metadata: type_metadata(cx, data_ptr_type, span),
offset: ComputedMemberOffset,
},
MemberDescription {
- name: ~"length",
+ name: "length".to_owned(),
llvm_type: *member_llvm_types.get(1),
type_metadata: type_metadata(cx, ty::mk_uint(), span),
offset: ComputedMemberOffset,
trait_type: ty::t,
substs: &ty::substs,
trait_store: ty::TraitStore,
- mutability: ast::Mutability,
_: &ty::BuiltinBounds)
-> DIType {
// The implementation provided here is a stub. It makes sure that the trait type is
let last = ty::with_path(cx.tcx(), def_id, |mut path| path.last().unwrap());
let ident_string = token::get_name(last.name());
let name = ppaux::trait_store_to_str(cx.tcx(), trait_store) +
- ppaux::mutability_to_str(mutability) +
ident_string.get();
// Add type and region parameters
let name = ppaux::parameterized(cx.tcx(), name, &substs.regions,
let trait_llvm_type = type_of::type_of(cx, trait_type);
- return composite_type_metadata(cx,
- trait_llvm_type,
- name,
- [],
- containing_scope,
- file_metadata,
- definition_span);
+ composite_type_metadata(cx,
+ trait_llvm_type,
+ name,
+ [],
+ containing_scope,
+ file_metadata,
+ definition_span)
}
fn type_metadata(cx: &CrateContext,
ty::ty_str(ref vstore) => {
let i8_t = ty::mk_i8();
match *vstore {
- ty::vstore_fixed(len) => {
+ ty::VstoreFixed(len) => {
fixed_vec_metadata(cx, i8_t, len, usage_site_span)
},
- ty::vstore_uniq => {
+ ty::VstoreUniq => {
let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
- ty::vstore_slice(_region) => {
+ ty::VstoreSlice(..) => {
vec_slice_metadata(cx, t, i8_t, usage_site_span)
}
}
ty::ty_box(typ) => {
create_pointer_to_box_metadata(cx, t, typ)
},
- ty::ty_vec(ref mt, ref vstore) => {
+ ty::ty_vec(ty, ref vstore) => {
match *vstore {
- ty::vstore_fixed(len) => {
- fixed_vec_metadata(cx, mt.ty, len, usage_site_span)
+ ty::VstoreFixed(len) => {
+ fixed_vec_metadata(cx, ty, len, usage_site_span)
}
- ty::vstore_uniq => {
- let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
+ ty::VstoreUniq => {
+ let vec_metadata = vec_metadata(cx, ty, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
- ty::vstore_slice(_) => {
- vec_slice_metadata(cx, t, mt.ty, usage_site_span)
+ ty::VstoreSlice(..) => {
+ vec_slice_metadata(cx, t, ty, usage_site_span)
}
}
},
ty::ty_closure(ref closurety) => {
subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
},
- ty::ty_trait(~ty::TyTrait { def_id, ref substs,
- store: trait_store, mutability,
- ref bounds }) => {
- trait_metadata(cx, def_id, t, substs, trait_store, mutability, bounds)
+ ty::ty_trait(~ty::TyTrait { def_id, ref substs, store, ref bounds }) => {
+ trait_metadata(cx, def_id, t, substs, store, bounds)
},
ty::ty_struct(def_id, ref substs) => {
if ty::type_is_simd(cx.tcx(), t) {
}
fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
- match fcx.debug_context {
+ match fcx.debug_context.repr {
FunctionDebugContext(_) => false,
_ => true
}
walk_expr(cx, rhs, scope_stack, scope_map);
}
- ast::ExprVec(ref init_expressions, _) |
- ast::ExprTup(ref init_expressions) => {
+ ast::ExprVec(ref init_expressions) |
+ ast::ExprTup(ref init_expressions) => {
for ie in init_expressions.iter() {
walk_expr(cx, *ie, scope_stack, scope_map);
}
}
- ast::ExprAssign(sub_exp1, sub_exp2) |
- ast::ExprRepeat(sub_exp1, sub_exp2, _) => {
+ ast::ExprAssign(sub_exp1, sub_exp2) |
+ ast::ExprRepeat(sub_exp1, sub_exp2) => {
walk_expr(cx, sub_exp1, scope_stack, scope_map);
walk_expr(cx, sub_exp2, scope_stack, scope_map);
}
impl NamespaceTreeNode {
fn mangled_name_of_contained_item(&self, item_name: &str) -> ~str {
- fn fill_nested(node: &NamespaceTreeNode, output: &mut ~str) {
+ fn fill_nested(node: &NamespaceTreeNode, output: &mut StrBuf) {
match node.parent {
Some(parent) => fill_nested(parent, output),
None => {}
output.push_str(string.get());
}
- let mut name = ~"_ZN";
+ let mut name = StrBuf::from_str("_ZN");
fill_nested(self, &mut name);
name.push_str(format!("{}", item_name.len()));
name.push_str(item_name);
name.push_char('E');
- name
+ name.into_owned()
}
}