Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Remove simplify_type and replace with sizing_type_of. rs=b... #4980

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,7 @@ pub fn trans_crate(sess: session::Session,
const_values: HashMap(),
module_data: HashMap(),
lltypes: ty::new_ty_hash(),
llsizingtypes: ty::new_ty_hash(),
names: new_namegen(sess.parse_sess.interner),
next_addrspace: new_addrspace_gen(),
symbol_hasher: symbol_hasher,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pub struct crate_ctxt {
const_values: HashMap<ast::node_id, ValueRef>,
module_data: HashMap<~str, ValueRef>,
lltypes: HashMap<ty::t, TypeRef>,
llsizingtypes: HashMap<ty::t, TypeRef>,
names: namegen,
next_addrspace: addrspace_gen,
symbol_hasher: @hash::State,
Expand Down
105 changes: 33 additions & 72 deletions src/librustc/middle/trans/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,8 @@

use middle::trans::common::*;
use middle::trans::type_of;
use middle::ty::field;
use middle::ty;

use syntax::parse::token::special_idents;

// Creates a simpler, size-equivalent type. The resulting type is guaranteed
// to have (a) the same size as the type that was passed in; (b) to be non-
// recursive. This is done by replacing all boxes in a type with boxed unit
// types.
// This should reduce all pointers to some simple pointer type, to
// ensure that we don't recurse endlessly when computing the size of a
// nominal type that has pointers to itself in it.
pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
fn nilptr(tcx: ty::ctxt) -> ty::t {
ty::mk_ptr(tcx, ty::mt {ty: ty::mk_nil(tcx), mutbl: ast::m_imm})
}
fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t {
match ty::get(typ).sty {
ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) |
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
ty::ty_ptr(_) | ty::ty_rptr(*) => nilptr(tcx),

ty::ty_bare_fn(*) | // FIXME(#4804) Bare fn repr
ty::ty_closure(*) => ty::mk_tup(tcx, ~[nilptr(tcx), nilptr(tcx)]),

ty::ty_evec(_, ty::vstore_slice(_)) |
ty::ty_estr(ty::vstore_slice(_)) => {
ty::mk_tup(tcx, ~[nilptr(tcx), ty::mk_int(tcx)])
}
// Reduce a class type to a record type in which all the fields are
// simplified
ty::ty_struct(did, ref substs) => {
let simpl_fields = (if ty::ty_dtor(tcx, did).is_present() {
// remember the drop flag
~[field {
ident: special_idents::dtor,
mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl}
}] }
else { ~[] }) +
do ty::lookup_struct_fields(tcx, did).map |f| {
let t = ty::lookup_field_type(tcx, did, f.id, substs);
field {
ident: f.ident,
mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const
}}
};
ty::mk_rec(tcx, simpl_fields)
}
_ => typ
}
}
ty::fold_ty(tcx, typ, |t| simplifier(tcx, t))
}
use util::ppaux::ty_to_str;

// ______________________________________________________________________
// compute sizeof / alignof
Expand Down Expand Up @@ -180,27 +128,40 @@ pub fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {

// Computes the size of the data part of an enum.
pub fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) -> uint {
if cx.enum_sizes.contains_key(&t) { return cx.enum_sizes.get(&t); }
if cx.enum_sizes.contains_key(&t) {
return cx.enum_sizes.get(&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 = 0u;
let variants = ty::enum_variants(cx.tcx, tid);
for vec::each(*variants) |variant| {
let tup_ty = simplify_type(
cx.tcx,
ty::mk_tup(cx.tcx, /*bad*/copy variant.args));
// Perform any type parameter substitutions.
let tup_ty = ty::subst(cx.tcx, substs, tup_ty);
// Here we possibly do a recursive call.
let this_size =
llsize_of_real(cx, type_of::type_of(cx, tup_ty));
if max_size < this_size { max_size = this_size; }
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.each |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),
ty_str(cx.tn, T_struct(lltypes)));

let this_size = llsize_of_real(cx, T_struct(lltypes));
if max_size < this_size {
max_size = this_size;
}
}
cx.enum_sizes.insert(t, max_size);
return max_size;
}
cx.enum_sizes.insert(t, max_size);
return max_size;
}
_ => cx.sess.bug(~"static_size_of_enum called on non-enum")
_ => cx.sess.bug(~"static_size_of_enum called on non-enum")
}
}

119 changes: 104 additions & 15 deletions src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,95 @@ pub fn type_of_non_gc_box(cx: @crate_ctxt, t: ty::t) -> TypeRef {
}
}

// A "sizing type" is an LLVM type, the size and alignment of which are
// guaranteed to be equivalent to what you would get out of `type_of()`. It's
// useful because:
//
// (1) It may be cheaper to compute the sizing type than the full type if all
// you're interested in is the size and/or alignment;
//
// (2) It won't make any recursive calls to determine the structure of the
// type behind pointers. This can help prevent infinite loops for
// recursive types. For example, `static_size_of_enum()` relies on this
// behavior.

pub fn sizing_type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
if cx.llsizingtypes.contains_key(&t) {
return cx.llsizingtypes.get(&t);
}

let llsizingty = match ty::get(t).sty {
ty::ty_nil | ty::ty_bot => T_nil(),
ty::ty_bool => T_bool(),
ty::ty_int(t) => T_int_ty(cx, t),
ty::ty_uint(t) => T_uint_ty(cx, t),
ty::ty_float(t) => T_float_ty(cx, t),

ty::ty_estr(ty::vstore_uniq) |
ty::ty_estr(ty::vstore_box) |
ty::ty_evec(_, ty::vstore_uniq) |
ty::ty_evec(_, ty::vstore_box) |
ty::ty_box(*) |
ty::ty_opaque_box |
ty::ty_uniq(*) |
ty::ty_ptr(*) |
ty::ty_rptr(*) |
ty::ty_type |
ty::ty_opaque_closure_ptr(*) => T_ptr(T_i8()),

ty::ty_estr(ty::vstore_slice(*)) |
ty::ty_evec(_, ty::vstore_slice(*)) => {
T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())])
}

// FIXME(#4804) Bare fn repr
ty::ty_bare_fn(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]),
ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]),
ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore),

ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size),
ty::ty_evec(mt, ty::vstore_fixed(size)) => {
T_array(sizing_type_of(cx, mt.ty), size)
}

ty::ty_unboxed_vec(mt) => T_vec(cx, sizing_type_of(cx, mt.ty)),

ty::ty_tup(ref elems) => {
T_struct(elems.map(|&t| sizing_type_of(cx, t)))
}

ty::ty_rec(ref fields) => {
T_struct(fields.map(|f| sizing_type_of(cx, f.mt.ty)))
}

ty::ty_struct(def_id, ref substs) => {
let fields = ty::lookup_struct_fields(cx.tcx, def_id);
let lltype = T_struct(fields.map(|field| {
let field_type = ty::lookup_field_type(cx.tcx,
def_id,
field.id,
substs);
sizing_type_of(cx, field_type)
}));
if ty::ty_dtor(cx.tcx, def_id).is_present() {
T_struct(~[lltype, T_i8()])
} else {
lltype
}
}

ty::ty_enum(def_id, _) => T_struct(enum_body_types(cx, def_id, t)),

ty::ty_self | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => {
cx.tcx.sess.bug(~"fictitious type in sizing_type_of()")
}
};

cx.llsizingtypes.insert(t, llsizingty);
llsizingty
}

// NB: If you update this, be sure to update `sizing_type_of()` as well.
pub fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
debug!("type_of %?: %?", t, ty::get(t));

Expand Down Expand Up @@ -236,23 +325,23 @@ pub fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
return llty;
}

pub fn fill_type_of_enum(cx: @crate_ctxt, did: ast::def_id, t: ty::t,
llty: TypeRef) {
pub fn enum_body_types(cx: @crate_ctxt, did: ast::def_id, t: ty::t)
-> ~[TypeRef] {
let univar = ty::enum_is_univariant(cx.tcx, did);
let size = machine::static_size_of_enum(cx, t);
if !univar {
~[T_enum_discrim(cx), T_array(T_i8(), size)]
} else {
~[T_array(T_i8(), size)]
}
}

pub fn fill_type_of_enum(cx: @crate_ctxt,
did: ast::def_id,
t: ty::t,
llty: TypeRef) {
debug!("type_of_enum %?: %?", t, ty::get(t));

let lltys = {
let univar = ty::enum_is_univariant(cx.tcx, did);
let size = machine::static_size_of_enum(cx, t);
if !univar {
~[T_enum_discrim(cx), T_array(T_i8(), size)]
}
else {
~[T_array(T_i8(), size)]
}
};

common::set_struct_body(llty, lltys);
common::set_struct_body(llty, enum_body_types(cx, did, t));
}

// Want refinements! (Or case classes, I guess
Expand Down