diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index aeb2017c9d6..215c002eec8 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1635,6 +1635,14 @@ pub mod llvm { #[fast_ffi] pub unsafe fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint; + + /** Computes the byte offset of the indexed struct element for a target. */ + #[fast_ffi] + pub unsafe fn LLVMOffsetOfElement(TD: TargetDataRef, + StructTy: TypeRef, + Element: c_uint) + -> c_ulonglong; + /** * Returns the minimum alignment of a type when part of a call frame. */ diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 00b59d187bf..74d8825d6d4 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -49,6 +49,7 @@ use lib::llvm::debuginfo::*; use middle::trans::common::*; use middle::trans::machine; use middle::trans::type_of; +use middle::trans::type_::Type; use middle::trans; use middle::ty; use util::ppaux::ty_to_str; @@ -65,6 +66,8 @@ use syntax::codemap::span; use syntax::{ast, codemap, ast_util, ast_map}; use syntax::parse::token; + + static DW_LANG_RUST: int = 0x9000; static AutoVariableTag: int = 256; @@ -594,17 +597,102 @@ fn create_struct(cx: &mut CrateContext, struct_type: ty::t, fields: ~[ty::field] -> DICompositeType { debug!("create_struct: %?", ty::get(struct_type)); - let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); + let struct_name = ty_to_str(cx.tcx, struct_type); + let struct_llvm_type = type_of::type_of(cx, struct_type); - let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, struct_type), file_md, loc.line); - for fields.iter().advance |field| { - let field_t = field.mt.ty; - let ty_md = create_ty(cx, field_t, span); - let (size, align) = size_and_align_of(cx, field_t); - scx.add_member(cx.sess.str_of(field.ident), loc.line, size, align, ty_md); - } - return scx.finalize(); + let field_llvm_types = fields.map(|field| type_of::type_of(cx, field.mt.ty)); + let field_names = fields.map(|field| cx.sess.str_of(field.ident).to_owned()); + let field_types_metadata = fields.map(|field| create_ty(cx, field.mt.ty, span)); + + return create_composite_type( + cx, + struct_llvm_type, + struct_name, + field_llvm_types, + field_names, + field_types_metadata, + span); +} + +fn create_tuple(cx: &mut CrateContext, + tuple_type: ty::t, + component_types: &[ty::t], + span: span) + -> DICompositeType { + + let tuple_name = (cx.sess.str_of((dbg_cx(cx).names)("tuple"))).to_owned(); + let tuple_llvm_type = type_of::type_of(cx, tuple_type); + // Create a vec of empty strings. A vec::build_n() function would be nice for this. + let mut component_names : ~[~str] = vec::with_capacity(component_types.len()); + component_names.grow_fn(component_types.len(), |_| ~""); + + let component_llvm_types = component_types.map(|it| type_of::type_of(cx, *it)); + let component_types_metadata = component_types.map(|it| create_ty(cx, *it, span)); + + return create_composite_type( + cx, + tuple_llvm_type, + tuple_name, + component_llvm_types, + component_names, + component_types_metadata, + span); +} + +fn create_composite_type(cx: &mut CrateContext, + composite_llvm_type: Type, + composite_type_name: &str, + member_llvm_types: &[Type], + member_names: &[~str], + member_type_metadata: &[DIType], + span: span) + -> DICompositeType { + + let loc = span_start(cx, span); + let file_metadata = create_file(cx, loc.file.name); + + let composite_size = machine::llsize_of_alloc(cx, composite_llvm_type); + let composite_align = machine::llalign_of_min(cx, composite_llvm_type); + + let member_metadata = create_DIArray( + DIB(cx), + // transform the ty::t array of components into an array of DIEs + do vec::mapi(member_llvm_types) |i, member_llvm_type| { + let member_size = machine::llsize_of_alloc(cx, *member_llvm_type); + let member_align = machine::llalign_of_min(cx, *member_llvm_type); + let member_offset = machine::llelement_offset(cx, composite_llvm_type, i); + let member_name : &str = member_names[i]; + + do member_name.as_c_str |member_name| { unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + file_metadata, + member_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + 0, + member_type_metadata[i]) + }} + }); + + return do composite_type_name.as_c_str |name| { unsafe { + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + file_metadata, + name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(composite_size), + bytes_to_bits(composite_align), + 0, + ptr::null(), + member_metadata, + 0, + ptr::null()) + }}; } // returns (void* type as a ValueRef, size in bytes, align in bytes) @@ -639,30 +727,83 @@ fn create_tuple(cx: &mut CrateContext, tuple_type: ty::t, elements: &[ty::t], sp return scx.finalize(); } -fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, - span: span, boxed: DIType) -> DICompositeType { - debug!("create_boxed_type: %?", ty::get(contents)); +fn create_boxed_type(cx: &mut CrateContext, + content_type: ty::t, + span: span) + -> DICompositeType { - let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); - let int_t = ty::mk_int(); - let refcount_type = create_basic_type(cx, int_t, span); - let name = ty_to_str(cx.tcx, contents); + debug!("create_boxed_type: %?", ty::get(content_type)); - let mut scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); - scx.add_member("refcnt", 0, sys::size_of::(), - sys::min_align_of::(), refcount_type); - // the tydesc and other pointers should be irrelevant to the - // debugger, so treat them as void* types - let (vp, vpsize, vpalign) = voidptr(cx); - scx.add_member("tydesc", 0, vpsize, vpalign, vp); - scx.add_member("prev", 0, vpsize, vpalign, vp); - scx.add_member("next", 0, vpsize, vpalign, vp); - let (size, align) = size_and_align_of(cx, contents); - scx.add_member("boxed", 0, size, align, boxed); - return scx.finalize(); + let content_llvm_type = type_of::type_of(cx, content_type); + let content_type_metadata = create_ty(cx, content_type, span); + + let box_llvm_type = Type::box(cx, &content_llvm_type); + let member_llvm_types = box_llvm_type.field_types(); + let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"]; + + assert!(box_layout_is_as_expected(cx, member_llvm_types, content_llvm_type)); + + let int_type = ty::mk_int(); + let nil_pointer_type = ty::mk_nil_ptr(cx.tcx); + + let member_types_metadata = [ + create_ty(cx, int_type, span), + create_ty(cx, nil_pointer_type, span), + create_ty(cx, nil_pointer_type, span), + create_ty(cx, nil_pointer_type, span), + content_type_metadata + ]; + + return create_composite_type( + cx, + box_llvm_type, + "box name", + member_llvm_types, + member_names, + member_types_metadata, + span); + + fn box_layout_is_as_expected(cx: &CrateContext, + member_types: &[Type], + content_type: Type) + -> bool { + return member_types[0] == cx.int_type + && member_types[1] == cx.tydesc_type.ptr_to() + && member_types[2] == Type::i8().ptr_to() + && member_types[3] == Type::i8().ptr_to() + && member_types[4] == content_type; + } } +// fn create_boxed_type(cx: &mut CrateContext, +// contents: ty::t, +// span: span, +// boxed: DIType) +// -> DICompositeType { + +// debug!("create_boxed_type: %?", ty::get(contents)); + +// let loc = span_start(cx, span); +// let file_md = create_file(cx, loc.file.name); +// let int_t = ty::mk_int(); +// let refcount_type = create_basic_type(cx, int_t, span); +// let name = ty_to_str(cx.tcx, contents); + +// let mut scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); +// scx.add_member("refcnt", 0, sys::size_of::(), +// sys::min_align_of::(), refcount_type); +// // the tydesc and other pointers should be irrelevant to the +// // debugger, so treat them as void* types +// let (vp, vpsize, vpalign) = voidptr(cx); +// scx.add_member("tydesc", 0, vpsize, vpalign, vp); +// scx.add_member("prev", 0, vpsize, vpalign, vp); +// scx.add_member("next", 0, vpsize, vpalign, vp); +// let (size, align) = size_and_align_of(cx, contents); +// scx.add_member("val", 0, size, align, boxed); +// return scx.finalize(); +// } + + fn create_fixed_vec(cx: &mut CrateContext, _vec_t: ty::t, elem_t: ty::t, len: uint, span: span) -> DIType { debug!("create_fixed_vec: %?", ty::get(_vec_t)); @@ -840,9 +981,8 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) -> DIType { create_unimpl_ty(cx, t) } ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => { - let boxed = create_ty(cx, mt.ty, span); - let box_md = create_boxed_type(cx, mt.ty, span, boxed); - create_pointer_type(cx, t, span, box_md) + let box_metadata = create_boxed_type(cx, mt.ty, span); + create_pointer_type(cx, t, span, box_metadata) }, ty::ty_evec(ref mt, ref vstore) => { match *vstore { @@ -858,10 +998,7 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) -> DIType { } } }, - ty::ty_ptr(ref mt) => { - let pointee = create_ty(cx, mt.ty, span); - create_pointer_type(cx, t, span, pointee) - }, + ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { let pointee = create_ty(cx, mt.ty, span); create_pointer_type(cx, t, span, pointee) diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 2cd313ff431..c0b57a22065 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -113,3 +113,48 @@ pub fn llalign_of(cx: &CrateContext, ty: Type) -> ValueRef { llvm::LLVMAlignOf(ty.to_ref()), cx.int_type.to_ref(), False); } } + +pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> uint { + unsafe { + return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as uint; + } +} + +// Computes the size of the data part of an enum. +pub fn static_size_of_enum(cx: &mut CrateContext, t: ty::t) -> uint { + if cx.enum_sizes.contains_key(&t) { + return cx.enum_sizes.get_copy(&t); + } + + debug!("static_size_of_enum %s", ty_to_str(cx.tcx, t)); + + match ty::get(t).sty { + ty::ty_enum(tid, ref substs) => { + // Compute max(variant sizes). + let mut max_size = 0; + let variants = ty::enum_variants(cx.tcx, tid); + for variants.iter().advance |variant| { + if variant.args.len() == 0 { + loop; + } + + let lltypes = variant.args.map(|&variant_arg| { + let substituted = ty::subst(cx.tcx, substs, variant_arg); + type_of::sizing_type_of(cx, substituted) + }); + + debug!("static_size_of_enum: variant %s type %s", + cx.tcx.sess.str_of(variant.name), + cx.tn.type_to_str(Type::struct_(lltypes, false))); + + let this_size = llsize_of_real(cx, Type::struct_(lltypes, false)); + if max_size < this_size { + max_size = this_size; + } + } + cx.enum_sizes.insert(t, max_size); + return max_size; + } + _ => cx.sess.bug("static_size_of_enum called on non-enum") + } +} diff --git a/src/test/debug-info/box.rs b/src/test/debug-info/box.rs index 4a3a65a9055..543d8f1cdb7 100644 --- a/src/test/debug-info/box.rs +++ b/src/test/debug-info/box.rs @@ -8,20 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - // compile-flags:-Z extra-debug-info // debugger:set print pretty off // debugger:break _zzz // debugger:run // debugger:finish -// debugger:print a->boxed +// debugger:print a->val // check:$1 = 1 -// debugger:print b->boxed +// debugger:print b->val // check:$2 = {2, 3.5} -// debugger:print c->boxed +// debugger:print c->val // check:$3 = 4 -// debugger:print d->boxed +// debugger:print d->val // check:$4 = false fn main() { diff --git a/src/test/debug-info/boxed-struct.rs b/src/test/debug-info/boxed-struct.rs new file mode 100644 index 00000000000..31b47462675 --- /dev/null +++ b/src/test/debug-info/boxed-struct.rs @@ -0,0 +1,60 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print unique->val +// check:$1 = {x = 99, y = 999, z = 9999, w = 99999} + +// debugger:print managed->val +// check:$2 = {x = 88, y = 888, z = 8888, w = 88888} + +// debugger:print unique_dtor->val +// check:$3 = {x = 77, y = 777, z = 7777, w = 77777} + +// debugger:print managed_dtor->val +// check:$4 = {x = 33, y = 333, z = 3333, w = 33333} + +struct StructWithSomePadding { + x: i16, + y: i32, + z: i32, + w: i64 +} + +struct StructWithDestructor { + x: i16, + y: i32, + z: i32, + w: i64 +} + +impl Drop for StructWithDestructor { + fn drop(&self) {} +} + +fn main() { + + let unique = ~StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; + let managed = @StructWithSomePadding { x: 88, y: 888, z: 8888, w: 88888 }; + + let unique_dtor = ~StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let managed_dtor = @StructWithDestructor { x: 33, y: 333, z: 3333, w: 33333 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-with-destructor.rs b/src/test/debug-info/struct-with-destructor.rs index f8281bba49e..9c72c676d54 100644 --- a/src/test/debug-info/struct-with-destructor.rs +++ b/src/test/debug-info/struct-with-destructor.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run @@ -34,7 +32,7 @@ struct WithDestructor { } impl Drop for WithDestructor { - fn finalize(&self) {} + fn drop(&self) {} } struct NoDestructorGuarded {