debuginfo: Began refactoring of composite type handling.
This commit is contained in:
parent
3514a5af06
commit
976d7a53cb
@ -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.
|
||||
*/
|
||||
|
@ -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::<uint>(),
|
||||
sys::min_align_of::<uint>(), 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::<uint>(),
|
||||
// sys::min_align_of::<uint>(), 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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
60
src/test/debug-info/boxed-struct.rs
Normal file
60
src/test/debug-info/boxed-struct.rs
Normal file
@ -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 <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.
|
||||
|
||||
// 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() {()}
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user