2011-08-04 12:46:10 -05:00
|
|
|
// A "shape" is a compact encoding of a type that is used by interpreted glue.
|
|
|
|
// This substitutes for the runtime tags used by e.g. MLs.
|
|
|
|
|
2012-09-04 13:54:36 -05:00
|
|
|
use lib::llvm::llvm;
|
|
|
|
use lib::llvm::{True, False, ModuleRef, TypeRef, ValueRef};
|
|
|
|
use driver::session;
|
|
|
|
use driver::session::session;
|
|
|
|
use trans::base;
|
|
|
|
use middle::trans::common::*;
|
|
|
|
use back::abi;
|
|
|
|
use middle::ty;
|
|
|
|
use middle::ty::field;
|
|
|
|
use syntax::ast;
|
|
|
|
use syntax::ast_util::{dummy_sp, new_def_hash};
|
|
|
|
use syntax::util::interner;
|
|
|
|
use util::ppaux::ty_to_str;
|
|
|
|
use syntax::codemap::span;
|
|
|
|
use dvec::DVec;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-09-04 13:54:36 -05:00
|
|
|
use std::map::hashmap;
|
|
|
|
use option::is_some;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-09-04 13:54:36 -05:00
|
|
|
use ty_ctxt = middle::ty::ctxt;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-09-07 19:24:02 -05:00
|
|
|
type nominal_id_ = {did: ast::def_id, parent_id: Option<ast::def_id>,
|
2012-06-29 18:26:56 -05:00
|
|
|
tps: ~[ty::t]};
|
2012-09-07 19:24:02 -05:00
|
|
|
type nominal_id = @nominal_id_;
|
|
|
|
|
|
|
|
impl nominal_id_ : core::cmp::Eq {
|
|
|
|
pure fn eq(&&other: nominal_id_) -> bool {
|
|
|
|
if self.did != other.did ||
|
|
|
|
self.parent_id != other.parent_id {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
do vec::all2(self.tps, other.tps) |m_tp, n_tp| {
|
|
|
|
ty::type_id(m_tp) == ty::type_id(n_tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pure fn ne(&&other: nominal_id_) -> bool {
|
|
|
|
! (self == other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl nominal_id_ : to_bytes::IterBytes {
|
|
|
|
fn iter_bytes(lsb0: bool, f: to_bytes::Cb) {
|
|
|
|
to_bytes::iter_bytes_2(&self.did, &self.parent_id, lsb0, f);
|
|
|
|
for self.tps.each |t| {
|
|
|
|
ty::type_id(t).iter_bytes(lsb0, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-29 17:04:22 -05:00
|
|
|
|
|
|
|
fn mk_nominal_id(tcx: ty::ctxt, did: ast::def_id,
|
2012-08-20 14:23:37 -05:00
|
|
|
parent_id: Option<ast::def_id>,
|
2012-06-29 18:26:56 -05:00
|
|
|
tps: ~[ty::t]) -> nominal_id {
|
2012-06-30 18:19:07 -05:00
|
|
|
let tps_norm = tps.map(|t| ty::normalize_ty(tcx, t));
|
2012-06-19 16:44:38 -05:00
|
|
|
@{did: did, parent_id: parent_id, tps: tps_norm}
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
|
|
|
|
2012-09-07 16:52:28 -05:00
|
|
|
fn new_nominal_id_hash<T: Copy>() -> hashmap<nominal_id, T> {
|
2012-09-07 19:24:02 -05:00
|
|
|
return hashmap();
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type enum_data = {did: ast::def_id, substs: ty::substs};
|
2011-08-19 17:16:48 -05:00
|
|
|
|
|
|
|
type ctxt =
|
2012-03-26 20:35:18 -05:00
|
|
|
{mut next_tag_id: u16,
|
2011-08-19 17:16:48 -05:00
|
|
|
pad: u16,
|
2012-05-29 17:04:22 -05:00
|
|
|
tag_id_to_index: hashmap<nominal_id, u16>,
|
2012-08-14 18:54:13 -05:00
|
|
|
tag_order: DVec<enum_data>,
|
2012-05-29 17:04:22 -05:00
|
|
|
resources: interner::interner<nominal_id>,
|
2011-08-19 17:16:48 -05:00
|
|
|
llshapetablesty: TypeRef,
|
|
|
|
llshapetables: ValueRef};
|
|
|
|
|
|
|
|
const shape_u8: u8 = 0u8;
|
|
|
|
const shape_u16: u8 = 1u8;
|
|
|
|
const shape_u32: u8 = 2u8;
|
|
|
|
const shape_u64: u8 = 3u8;
|
|
|
|
const shape_i8: u8 = 4u8;
|
|
|
|
const shape_i16: u8 = 5u8;
|
|
|
|
const shape_i32: u8 = 6u8;
|
|
|
|
const shape_i64: u8 = 7u8;
|
|
|
|
const shape_f32: u8 = 8u8;
|
|
|
|
const shape_f64: u8 = 9u8;
|
2012-02-08 14:06:08 -06:00
|
|
|
const shape_box: u8 = 10u8;
|
2012-01-25 07:34:31 -06:00
|
|
|
const shape_enum: u8 = 12u8;
|
2011-08-19 17:16:48 -05:00
|
|
|
const shape_struct: u8 = 17u8;
|
2012-01-11 23:31:36 -06:00
|
|
|
const shape_box_fn: u8 = 18u8;
|
2011-08-19 17:16:48 -05:00
|
|
|
const shape_res: u8 = 20u8;
|
|
|
|
const shape_uniq: u8 = 22u8;
|
2012-01-05 18:19:12 -06:00
|
|
|
const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
|
2012-01-11 23:31:36 -06:00
|
|
|
const shape_uniq_fn: u8 = 25u8;
|
|
|
|
const shape_stack_fn: u8 = 26u8;
|
|
|
|
const shape_bare_fn: u8 = 27u8;
|
|
|
|
const shape_tydesc: u8 = 28u8;
|
|
|
|
const shape_send_tydesc: u8 = 29u8;
|
2012-03-08 16:05:16 -06:00
|
|
|
const shape_rptr: u8 = 31u8;
|
2012-04-09 19:32:49 -05:00
|
|
|
const shape_fixedvec: u8 = 32u8;
|
|
|
|
const shape_slice: u8 = 33u8;
|
2012-06-11 18:51:21 -05:00
|
|
|
const shape_unboxed_vec: u8 = 34u8;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn mk_global(ccx: @crate_ctxt, name: ~str, llval: ValueRef, internal: bool) ->
|
2011-10-12 15:31:41 -05:00
|
|
|
ValueRef {
|
2011-09-02 17:34:58 -05:00
|
|
|
let llglobal =
|
2012-03-14 17:10:34 -05:00
|
|
|
str::as_c_str(name,
|
2012-06-30 18:19:07 -05:00
|
|
|
|buf| {
|
2011-09-02 17:34:58 -05:00
|
|
|
lib::llvm::llvm::LLVMAddGlobal(ccx.llmod,
|
|
|
|
val_ty(llval), buf)
|
|
|
|
});
|
2011-08-04 12:46:10 -05:00
|
|
|
lib::llvm::llvm::LLVMSetInitializer(llglobal, llval);
|
|
|
|
lib::llvm::llvm::LLVMSetGlobalConstant(llglobal, True);
|
2011-08-20 16:22:09 -05:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
if internal {
|
2012-02-01 04:04:56 -06:00
|
|
|
lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
|
2011-08-20 16:22:09 -05:00
|
|
|
}
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return llglobal;
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
// Computes a set of variants of a enum that are guaranteed to have size and
|
|
|
|
// alignment at least as large as any other variant of the enum. This is an
|
2011-08-04 12:46:10 -05:00
|
|
|
// important performance optimization.
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
fn round_up(size: u16, align: u8) -> u16 {
|
|
|
|
assert (align >= 1u8);
|
2011-08-04 12:46:10 -05:00
|
|
|
let alignment = align as u16;
|
2012-08-01 19:30:05 -05:00
|
|
|
return size - 1u16 + alignment & !(alignment - 1u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
type size_align = {size: u16, align: u8};
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-01-25 07:34:31 -06:00
|
|
|
enum enum_kind {
|
2012-01-19 12:37:40 -06:00
|
|
|
tk_unit, // 1 variant, no data
|
|
|
|
tk_enum, // N variants, no data
|
|
|
|
tk_newtype, // 1 variant, data
|
|
|
|
tk_complex // N variants, no data
|
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn enum_kind(ccx: @crate_ctxt, did: ast::def_id) -> enum_kind {
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2012-06-30 18:19:07 -05:00
|
|
|
if vec::any(*variants, |v| vec::len(v.args) > 0u) {
|
2012-01-19 12:37:40 -06:00
|
|
|
if vec::len(*variants) == 1u { tk_newtype }
|
|
|
|
else { tk_complex }
|
|
|
|
} else {
|
|
|
|
if vec::len(*variants) <= 1u { tk_unit }
|
|
|
|
else { tk_enum }
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the code corresponding to the pointer size on this architecture.
|
2011-11-14 21:37:35 -06:00
|
|
|
fn s_int(tcx: ty_ctxt) -> u8 {
|
2012-08-06 14:34:08 -05:00
|
|
|
return match tcx.sess.targ_cfg.arch {
|
2012-08-03 21:59:04 -05:00
|
|
|
session::arch_x86 => shape_i32,
|
|
|
|
session::arch_x86_64 => shape_i64,
|
|
|
|
session::arch_arm => shape_i32
|
2011-11-14 21:37:35 -06:00
|
|
|
};
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-11-14 21:37:35 -06:00
|
|
|
fn s_uint(tcx: ty_ctxt) -> u8 {
|
2012-08-06 14:34:08 -05:00
|
|
|
return match tcx.sess.targ_cfg.arch {
|
2012-08-03 21:59:04 -05:00
|
|
|
session::arch_x86 => shape_u32,
|
|
|
|
session::arch_x86_64 => shape_u64,
|
|
|
|
session::arch_arm => shape_u32
|
2011-11-14 21:37:35 -06:00
|
|
|
};
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-11-14 21:37:35 -06:00
|
|
|
fn s_float(tcx: ty_ctxt) -> u8 {
|
2012-08-06 14:34:08 -05:00
|
|
|
return match tcx.sess.targ_cfg.arch {
|
2012-08-03 21:59:04 -05:00
|
|
|
session::arch_x86 => shape_f64,
|
|
|
|
session::arch_x86_64 => shape_f64,
|
|
|
|
session::arch_arm => shape_f64
|
2011-11-14 21:37:35 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-01-25 07:34:31 -06:00
|
|
|
fn s_variant_enum_t(tcx: ty_ctxt) -> u8 {
|
2012-08-01 19:30:05 -05:00
|
|
|
return s_int(tcx);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 23:31:36 -06:00
|
|
|
fn s_tydesc(_tcx: ty_ctxt) -> u8 {
|
2012-08-01 19:30:05 -05:00
|
|
|
return shape_tydesc;
|
2012-01-11 23:31:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn s_send_tydesc(_tcx: ty_ctxt) -> u8 {
|
2012-08-01 19:30:05 -05:00
|
|
|
return shape_send_tydesc;
|
2012-01-11 23:31:36 -06:00
|
|
|
}
|
|
|
|
|
2011-10-12 15:31:41 -05:00
|
|
|
fn mk_ctxt(llmod: ModuleRef) -> ctxt {
|
2012-07-14 00:57:48 -05:00
|
|
|
let llshapetablesty = trans::common::T_named_struct(~"shapes");
|
|
|
|
let llshapetables = str::as_c_str(~"shapes", |buf| {
|
2012-01-27 06:17:06 -06:00
|
|
|
lib::llvm::llvm::LLVMAddGlobal(llmod, llshapetablesty, buf)
|
|
|
|
});
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return {mut next_tag_id: 0u16,
|
2011-08-19 17:16:48 -05:00
|
|
|
pad: 0u16,
|
2012-05-29 17:04:22 -05:00
|
|
|
tag_id_to_index: new_nominal_id_hash(),
|
2012-08-27 16:22:25 -05:00
|
|
|
tag_order: DVec(),
|
2012-09-07 19:24:02 -05:00
|
|
|
resources: interner::mk(),
|
2011-08-19 17:16:48 -05:00
|
|
|
llshapetablesty: llshapetablesty,
|
|
|
|
llshapetables: llshapetables};
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn add_bool(&dest: ~[u8], val: bool) {
|
|
|
|
dest += ~[if val { 1u8 } else { 0u8 }];
|
2012-06-25 22:00:46 -05:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn add_u16(&dest: ~[u8], val: u16) {
|
|
|
|
dest += ~[(val & 0xffu16) as u8, (val >> 8u16) as u8];
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn add_substr(&dest: ~[u8], src: ~[u8]) {
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(dest, vec::len(src) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
dest += src;
|
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn shape_of(ccx: @crate_ctxt, t: ty::t) -> ~[u8] {
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty::get(t).struct {
|
2012-09-07 09:37:19 -05:00
|
|
|
ty::ty_nil | ty::ty_bool | ty::ty_uint(ast::ty_u8) |
|
|
|
|
ty::ty_bot => ~[shape_u8],
|
|
|
|
ty::ty_int(ast::ty_i) => ~[s_int(ccx.tcx)],
|
|
|
|
ty::ty_float(ast::ty_f) => ~[s_float(ccx.tcx)],
|
|
|
|
ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) => ~[s_uint(ccx.tcx)],
|
|
|
|
ty::ty_type => ~[s_tydesc(ccx.tcx)],
|
|
|
|
ty::ty_int(ast::ty_i8) => ~[shape_i8],
|
|
|
|
ty::ty_uint(ast::ty_u16) => ~[shape_u16],
|
|
|
|
ty::ty_int(ast::ty_i16) => ~[shape_i16],
|
|
|
|
ty::ty_uint(ast::ty_u32) => ~[shape_u32],
|
|
|
|
ty::ty_int(ast::ty_i32) | ty::ty_int(ast::ty_char) => ~[shape_i32],
|
|
|
|
ty::ty_uint(ast::ty_u64) => ~[shape_u64],
|
|
|
|
ty::ty_int(ast::ty_i64) => ~[shape_i64],
|
|
|
|
ty::ty_float(ast::ty_f32) => ~[shape_f32],
|
|
|
|
ty::ty_float(ast::ty_f64) => ~[shape_f64],
|
|
|
|
ty::ty_estr(ty::vstore_uniq) => {
|
|
|
|
shape_of(ccx, tvec::expand_boxed_vec_ty(ccx.tcx, t))
|
|
|
|
}
|
|
|
|
ty::ty_enum(did, substs) => {
|
|
|
|
match enum_kind(ccx, did) {
|
|
|
|
tk_unit => ~[s_variant_enum_t(ccx.tcx)],
|
|
|
|
tk_enum => ~[s_variant_enum_t(ccx.tcx)],
|
|
|
|
tk_newtype | tk_complex => {
|
|
|
|
let mut s = ~[shape_enum], id;
|
|
|
|
let nom_id = mk_nominal_id(ccx.tcx, did,
|
|
|
|
None, substs.tps);
|
|
|
|
match ccx.shape_cx.tag_id_to_index.find(nom_id) {
|
|
|
|
None => {
|
|
|
|
id = ccx.shape_cx.next_tag_id;
|
|
|
|
ccx.shape_cx.tag_id_to_index.insert(nom_id, id);
|
|
|
|
ccx.shape_cx.tag_order.push({did: did,
|
|
|
|
substs: substs});
|
|
|
|
ccx.shape_cx.next_tag_id += 1u16;
|
|
|
|
}
|
|
|
|
Some(existing_id) => id = existing_id,
|
|
|
|
}
|
|
|
|
add_u16(s, id as u16);
|
|
|
|
|
|
|
|
s
|
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2012-09-07 09:37:19 -05:00
|
|
|
}
|
|
|
|
ty::ty_estr(ty::vstore_box) |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) |
|
|
|
|
ty::ty_box(_) | ty::ty_opaque_box => ~[shape_box],
|
|
|
|
ty::ty_uniq(mt) => {
|
|
|
|
let mut s = ~[shape_uniq];
|
|
|
|
add_substr(s, shape_of(ccx, mt.ty));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
ty::ty_unboxed_vec(mt) => {
|
|
|
|
let mut s = ~[shape_unboxed_vec];
|
|
|
|
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
|
|
|
|
add_substr(s, shape_of(ccx, mt.ty));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) => {
|
|
|
|
shape_of(ccx, tvec::expand_boxed_vec_ty(ccx.tcx, t))
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_estr(ty::vstore_fixed(n)) => {
|
|
|
|
let mut s = ~[shape_fixedvec];
|
|
|
|
let u8_t = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
|
|
|
|
assert (n + 1u) <= 0xffffu;
|
|
|
|
add_u16(s, (n + 1u) as u16);
|
|
|
|
add_bool(s, true);
|
|
|
|
add_substr(s, shape_of(ccx, u8_t));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_evec(mt, ty::vstore_fixed(n)) => {
|
|
|
|
let mut s = ~[shape_fixedvec];
|
|
|
|
assert n <= 0xffffu;
|
|
|
|
add_u16(s, n as u16);
|
|
|
|
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
|
|
|
|
add_substr(s, shape_of(ccx, mt.ty));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_estr(ty::vstore_slice(_)) => {
|
|
|
|
let mut s = ~[shape_slice];
|
|
|
|
let u8_t = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
|
|
|
|
add_bool(s, true); // is_pod
|
|
|
|
add_bool(s, true); // is_str
|
|
|
|
add_substr(s, shape_of(ccx, u8_t));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_evec(mt, ty::vstore_slice(_)) => {
|
|
|
|
let mut s = ~[shape_slice];
|
|
|
|
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
|
|
|
|
add_bool(s, false); // is_str
|
|
|
|
add_substr(s, shape_of(ccx, mt.ty));
|
|
|
|
s
|
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-09-07 09:37:19 -05:00
|
|
|
ty::ty_rec(fields) => {
|
|
|
|
let mut s = ~[shape_struct], sub = ~[];
|
|
|
|
for vec::each(fields) |f| {
|
|
|
|
sub += shape_of(ccx, f.mt.ty);
|
|
|
|
}
|
|
|
|
add_substr(s, sub);
|
2012-03-12 04:05:15 -05:00
|
|
|
s
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2012-09-07 09:37:19 -05:00
|
|
|
ty::ty_tup(elts) => {
|
|
|
|
let mut s = ~[shape_struct], sub = ~[];
|
|
|
|
for vec::each(elts) |elt| {
|
|
|
|
sub += shape_of(ccx, elt);
|
|
|
|
}
|
|
|
|
add_substr(s, sub);
|
|
|
|
s
|
2011-09-02 12:16:41 -05:00
|
|
|
}
|
2012-09-07 09:37:19 -05:00
|
|
|
ty::ty_trait(_, _, _) => ~[shape_box_fn],
|
|
|
|
ty::ty_class(did, ref substs) => {
|
|
|
|
// same as records, unless there's a dtor
|
|
|
|
let tps = substs.tps;
|
|
|
|
let m_dtor_did = ty::ty_dtor(ccx.tcx, did);
|
|
|
|
let mut s = if option::is_some(m_dtor_did) {
|
|
|
|
~[shape_res]
|
|
|
|
}
|
|
|
|
else { ~[shape_struct] }, sub = ~[];
|
|
|
|
do option::iter(m_dtor_did) |dtor_did| {
|
|
|
|
let ri = @{did: dtor_did, parent_id: Some(did), tps: tps};
|
|
|
|
let id = ccx.shape_cx.resources.intern(ri);
|
|
|
|
add_u16(s, id as u16);
|
|
|
|
};
|
|
|
|
for ty::class_items_as_mutable_fields(ccx.tcx, did,
|
|
|
|
substs).each |f| {
|
|
|
|
sub += shape_of(ccx, f.mt.ty);
|
|
|
|
}
|
|
|
|
add_substr(s, sub);
|
|
|
|
s
|
|
|
|
}
|
|
|
|
ty::ty_rptr(_, mt) => {
|
|
|
|
let mut s = ~[shape_rptr];
|
|
|
|
add_substr(s, shape_of(ccx, mt.ty));
|
|
|
|
s
|
|
|
|
}
|
|
|
|
ty::ty_param(*) => {
|
|
|
|
ccx.tcx.sess.bug(~"non-monomorphized type parameter");
|
|
|
|
}
|
|
|
|
ty::ty_fn(ref fn_ty) => {
|
|
|
|
match fn_ty.meta.proto {
|
|
|
|
ty::proto_vstore(ty::vstore_box) => ~[shape_box_fn],
|
|
|
|
ty::proto_vstore(ty::vstore_uniq) => ~[shape_uniq_fn],
|
|
|
|
ty::proto_vstore(ty::vstore_slice(_)) => ~[shape_stack_fn],
|
|
|
|
ty::proto_bare => ~[shape_bare_fn],
|
|
|
|
ty::proto_vstore(ty::vstore_fixed(_)) =>
|
|
|
|
fail ~"fixed vstore is impossible",
|
|
|
|
}
|
2011-09-22 18:10:48 -05:00
|
|
|
}
|
2012-09-07 09:37:19 -05:00
|
|
|
ty::ty_opaque_closure_ptr(_) => ~[shape_opaque_closure_ptr],
|
|
|
|
ty::ty_infer(_) | ty::ty_self => {
|
|
|
|
ccx.sess.bug(~"shape_of: unexpected type struct found")
|
2012-03-28 00:08:48 -05:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn shape_of_variant(ccx: @crate_ctxt, v: ty::variant_info) -> ~[u8] {
|
|
|
|
let mut s = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(v.args) |t| { s += shape_of(ccx, t); }
|
2012-08-01 19:30:05 -05:00
|
|
|
return s;
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
2012-01-25 07:34:31 -06:00
|
|
|
// Loop over all the enum variants and write their shapes into a
|
|
|
|
// data buffer. As we do this, it's possible for us to discover
|
|
|
|
// new enums, so we must do this first.
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut data = ~[];
|
|
|
|
let mut offsets = ~[];
|
2012-05-29 17:04:22 -05:00
|
|
|
let mut i = 0u;
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut enum_variants = ~[];
|
2012-05-10 11:27:02 -05:00
|
|
|
while i < ccx.shape_cx.tag_order.len() {
|
2012-05-29 17:04:22 -05:00
|
|
|
let {did, substs} = ccx.shape_cx.tag_order[i];
|
2012-08-10 12:49:31 -05:00
|
|
|
let variants = @ty::substd_enum_variants(ccx.tcx, did, &substs);
|
2012-06-30 18:19:07 -05:00
|
|
|
do vec::iter(*variants) |v| {
|
2012-06-29 18:26:56 -05:00
|
|
|
offsets += ~[vec::len(data) as u16];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-05-29 17:04:22 -05:00
|
|
|
let variant_shape = shape_of_variant(ccx, v);
|
2011-08-04 12:46:10 -05:00
|
|
|
add_substr(data, variant_shape);
|
2012-01-15 23:42:10 -06:00
|
|
|
|
2012-08-23 17:44:57 -05:00
|
|
|
let zname = str::to_bytes(ccx.sess.str_of(v.name)) + ~[0u8];
|
2012-01-15 23:42:10 -06:00
|
|
|
add_substr(data, zname);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2012-06-29 18:26:56 -05:00
|
|
|
enum_variants += ~[variants];
|
2011-08-04 12:46:10 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now calculate the sizes of the header space (which contains offsets to
|
2012-01-19 16:24:03 -06:00
|
|
|
// info records for each enum) and the info space (which contains offsets
|
2011-08-04 12:46:10 -05:00
|
|
|
// to each variant shape). As we do so, build up the header.
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut header = ~[];
|
|
|
|
let mut inf = ~[];
|
2011-08-04 12:46:10 -05:00
|
|
|
let header_sz = 2u16 * ccx.shape_cx.next_tag_id;
|
2011-08-15 18:38:23 -05:00
|
|
|
let data_sz = vec::len(data) as u16;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-04-19 18:19:53 -05:00
|
|
|
let mut inf_sz = 0u16;
|
2012-06-30 18:19:07 -05:00
|
|
|
for enum_variants.each |variants| {
|
2012-05-29 17:04:22 -05:00
|
|
|
let num_variants = vec::len(*variants) as u16;
|
2012-04-19 18:19:53 -05:00
|
|
|
add_u16(header, header_sz + inf_sz);
|
|
|
|
inf_sz += 2u16 * (num_variants + 2u16) + 3u16;
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the info tables, which contain offsets to the shape of each
|
2012-01-19 16:24:03 -06:00
|
|
|
// variant. Also construct the largest-variant table for each enum, which
|
2011-08-04 12:46:10 -05:00
|
|
|
// contains the variants that the size-of operation needs to look at.
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut lv_table = ~[];
|
2012-05-29 17:04:22 -05:00
|
|
|
let mut i = 0u;
|
2012-06-30 18:19:07 -05:00
|
|
|
for enum_variants.each |variants| {
|
2012-04-19 18:19:53 -05:00
|
|
|
add_u16(inf, vec::len(*variants) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
// Construct the largest-variants table.
|
2012-04-19 18:19:53 -05:00
|
|
|
add_u16(inf,
|
|
|
|
header_sz + inf_sz + data_sz + (vec::len(lv_table) as u16));
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-05-29 17:04:22 -05:00
|
|
|
let lv = largest_variants(ccx, variants);
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(lv_table, vec::len(lv) as u16);
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(lv) |v| { add_u16(lv_table, v as u16); }
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
// Determine whether the enum has dynamic size.
|
2012-06-30 18:19:07 -05:00
|
|
|
assert !vec::any(*variants, |v| {
|
|
|
|
vec::any(v.args, |t| ty::type_has_params(t))
|
2012-03-12 04:05:15 -05:00
|
|
|
});
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
// If we can, write in the static size and alignment of the enum.
|
2011-08-04 12:46:10 -05:00
|
|
|
// Otherwise, write a placeholder.
|
2012-05-29 17:04:22 -05:00
|
|
|
let size_align = compute_static_enum_size(ccx, lv, variants);
|
|
|
|
|
2012-03-12 04:05:15 -05:00
|
|
|
// Write in the static size and alignment of the enum.
|
2012-04-19 18:19:53 -05:00
|
|
|
add_u16(inf, size_align.size);
|
2012-06-29 18:26:56 -05:00
|
|
|
inf += ~[size_align.align];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
// Now write in the offset of each variant.
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(*variants) |_v| {
|
2012-04-19 18:19:53 -05:00
|
|
|
add_u16(inf, header_sz + inf_sz + offsets[i]);
|
2011-08-04 12:46:10 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-15 18:38:23 -05:00
|
|
|
assert (i == vec::len(offsets));
|
2011-08-19 17:16:48 -05:00
|
|
|
assert (header_sz == vec::len(header) as u16);
|
2012-04-19 18:19:53 -05:00
|
|
|
assert (inf_sz == vec::len(inf) as u16);
|
2011-08-19 17:16:48 -05:00
|
|
|
assert (data_sz == vec::len(data) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-04-19 18:19:53 -05:00
|
|
|
header += inf;
|
2011-08-04 12:46:10 -05:00
|
|
|
header += data;
|
|
|
|
header += lv_table;
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return mk_global(ccx, ~"tag_shapes", C_bytes(header), true);
|
2012-05-29 17:04:22 -05:00
|
|
|
|
2012-06-07 15:49:01 -05:00
|
|
|
/* tjc: Not annotating FIXMEs in this module because of #1498 */
|
2012-05-29 17:04:22 -05:00
|
|
|
fn largest_variants(ccx: @crate_ctxt,
|
2012-06-29 18:26:56 -05:00
|
|
|
variants: @~[ty::variant_info]) -> ~[uint] {
|
2012-05-29 17:04:22 -05:00
|
|
|
// Compute the minimum and maximum size and alignment for each
|
|
|
|
// variant.
|
|
|
|
//
|
2012-06-21 18:44:10 -05:00
|
|
|
// NB: We could do better here; e.g. we know that any
|
2012-05-29 17:04:22 -05:00
|
|
|
// variant that contains (T,T) must be as least as large as
|
|
|
|
// any variant that contains just T.
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut ranges = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(*variants) |variant| {
|
2012-05-29 17:04:22 -05:00
|
|
|
let mut bounded = true;
|
|
|
|
let mut min_size = 0u, min_align = 0u;
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(variant.args) |elem_t| {
|
2012-05-29 17:04:22 -05:00
|
|
|
if ty::type_has_params(elem_t) {
|
2012-06-21 18:44:10 -05:00
|
|
|
// NB: We could do better here; this causes us to
|
2012-05-29 17:04:22 -05:00
|
|
|
// conservatively assume that (int, T) has minimum size 0,
|
|
|
|
// when in fact it has minimum size sizeof(int).
|
|
|
|
bounded = false;
|
|
|
|
} else {
|
|
|
|
let llty = type_of::type_of(ccx, elem_t);
|
|
|
|
min_size += llsize_of_real(ccx, llty);
|
|
|
|
min_align += llalign_of_pref(ccx, llty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ranges +=
|
2012-06-29 18:26:56 -05:00
|
|
|
~[{size: {min: min_size, bounded: bounded},
|
|
|
|
align: {min: min_align, bounded: bounded}}];
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the candidate set to contain all variants.
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut candidates = ~[mut];
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(*variants) |_v| { candidates += ~[mut true]; }
|
2012-05-29 17:04:22 -05:00
|
|
|
|
|
|
|
// Do a pairwise comparison among all variants still in the
|
|
|
|
// candidate set. Throw out any variant that we know has size
|
|
|
|
// and alignment at least as small as some other variant.
|
|
|
|
let mut i = 0u;
|
|
|
|
while i < vec::len(ranges) - 1u {
|
|
|
|
if candidates[i] {
|
|
|
|
let mut j = i + 1u;
|
|
|
|
while j < vec::len(ranges) {
|
|
|
|
if candidates[j] {
|
|
|
|
if ranges[i].size.bounded &&
|
|
|
|
ranges[i].align.bounded &&
|
|
|
|
ranges[j].size.bounded &&
|
|
|
|
ranges[j].align.bounded {
|
2012-09-07 20:53:14 -05:00
|
|
|
if ranges[i].size.min >= ranges[j].size.min &&
|
|
|
|
ranges[i].align.min >= ranges[j].align.min {
|
2012-05-29 17:04:22 -05:00
|
|
|
// Throw out j.
|
|
|
|
candidates[j] = false;
|
2012-09-07 20:53:14 -05:00
|
|
|
} else if ranges[j].size.min >=
|
|
|
|
ranges[i].size.min &&
|
|
|
|
ranges[j].align.min >=
|
|
|
|
ranges[j].align.min {
|
2012-05-29 17:04:22 -05:00
|
|
|
// Throw out i.
|
|
|
|
candidates[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the resulting set.
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut result = ~[];
|
2012-05-29 17:04:22 -05:00
|
|
|
let mut i = 0u;
|
|
|
|
while i < vec::len(candidates) {
|
2012-06-25 22:00:46 -05:00
|
|
|
if candidates[i] { vec::push(result, i); }
|
2012-05-29 17:04:22 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return result;
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn compute_static_enum_size(ccx: @crate_ctxt, largest_variants: ~[uint],
|
|
|
|
variants: @~[ty::variant_info])
|
2012-06-25 22:00:46 -05:00
|
|
|
-> size_align {
|
2012-05-29 17:04:22 -05:00
|
|
|
let mut max_size = 0u16;
|
|
|
|
let mut max_align = 1u8;
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(largest_variants) |vid| {
|
2012-05-29 17:04:22 -05:00
|
|
|
// We increment a "virtual data pointer" to compute the size.
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut lltys = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(variants[vid].args) |typ| {
|
2012-06-29 18:26:56 -05:00
|
|
|
lltys += ~[type_of::type_of(ccx, typ)];
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let llty = trans::common::T_struct(lltys);
|
|
|
|
let dp = llsize_of_real(ccx, llty) as u16;
|
|
|
|
let variant_align = llalign_of_pref(ccx, llty) as u8;
|
|
|
|
|
|
|
|
if max_size < dp { max_size = dp; }
|
|
|
|
if max_align < variant_align { max_align = variant_align; }
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add space for the enum if applicable.
|
|
|
|
// FIXME (issue #792): This is wrong. If the enum starts with an
|
|
|
|
// 8 byte aligned quantity, we don't align it.
|
|
|
|
if vec::len(*variants) > 1u {
|
|
|
|
let variant_t = T_enum_discrim(ccx);
|
|
|
|
max_size += llsize_of_real(ccx, variant_t) as u16;
|
|
|
|
let align = llalign_of_pref(ccx, variant_t) as u8;
|
|
|
|
if max_align < align { max_align = align; }
|
|
|
|
}
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return {size: max_size, align: max_align};
|
2012-05-29 17:04:22 -05:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut dtors = ~[];
|
2012-07-17 13:22:11 -05:00
|
|
|
let len = ccx.shape_cx.resources.len();
|
2012-06-30 18:19:07 -05:00
|
|
|
for uint::range(0u, len) |i| {
|
2012-07-17 13:22:11 -05:00
|
|
|
let ri = ccx.shape_cx.resources.get(i);
|
2012-06-30 18:19:07 -05:00
|
|
|
for ri.tps.each() |s| { assert !ty::type_has_params(s); }
|
|
|
|
do option::iter(ri.parent_id) |id| {
|
2012-06-29 18:26:56 -05:00
|
|
|
dtors += ~[trans::base::get_res_dtor(ccx, ri.did, id, ri.tps)];
|
2012-06-24 17:09:57 -05:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return mk_global(ccx, ~"resource_shapes", C_struct(dtors), true);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-08-24 17:31:33 -05:00
|
|
|
// This function serves to break a cyclical dependence between
|
|
|
|
// emit_tydescs and gen_shape_tables.
|
|
|
|
//
|
|
|
|
// * emit_tydescs calls shape_of, which causes changes to the shape
|
|
|
|
// tables
|
|
|
|
// * gen_shape_tables transitively calls get_tydesc, which causes new
|
|
|
|
// tydescs to be created
|
|
|
|
//
|
|
|
|
// We force those tydescs to be emitted now, thus breaking the
|
|
|
|
// dependency.
|
|
|
|
fn force_declare_tydescs(ccx: @crate_ctxt) {
|
|
|
|
// Walk all known tydescs first to force shape code to declare
|
|
|
|
// dependencies.
|
|
|
|
for ccx.tydescs.each |key, _val| {
|
|
|
|
shape_of(ccx, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then walk all resource shapes to force emit all dtors.
|
|
|
|
let len = ccx.shape_cx.resources.len();
|
|
|
|
for uint::range(0u, len) |i| {
|
|
|
|
let ri = ccx.shape_cx.resources.get(i);
|
|
|
|
for ri.tps.each() |s| { assert !ty::type_has_params(s); }
|
|
|
|
do option::iter(ri.parent_id) |id| {
|
|
|
|
trans::base::get_res_dtor(ccx, ri.did, id, ri.tps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn gen_shape_tables(ccx: @crate_ctxt) {
|
2012-01-25 07:34:31 -06:00
|
|
|
let lltagstable = gen_enum_shapes(ccx);
|
2011-08-04 12:46:10 -05:00
|
|
|
let llresourcestable = gen_resource_shapes(ccx);
|
2012-01-27 06:17:06 -06:00
|
|
|
trans::common::set_struct_body(ccx.shape_cx.llshapetablesty,
|
2012-06-29 18:26:56 -05:00
|
|
|
~[val_ty(lltagstable),
|
|
|
|
val_ty(llresourcestable)]);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
let lltables =
|
|
|
|
C_named_struct(ccx.shape_cx.llshapetablesty,
|
2012-06-29 18:26:56 -05:00
|
|
|
~[lltagstable, llresourcestable]);
|
2011-08-04 12:46:10 -05:00
|
|
|
lib::llvm::llvm::LLVMSetInitializer(ccx.shape_cx.llshapetables, lltables);
|
|
|
|
lib::llvm::llvm::LLVMSetGlobalConstant(ccx.shape_cx.llshapetables, True);
|
2012-02-01 04:04:56 -06:00
|
|
|
lib::llvm::SetLinkage(ccx.shape_cx.llshapetables,
|
|
|
|
lib::llvm::InternalLinkage);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-01-19 12:21:42 -06:00
|
|
|
// ______________________________________________________________________
|
|
|
|
// compute sizeof / alignof
|
|
|
|
|
2012-01-19 12:37:40 -06:00
|
|
|
type metrics = {
|
2012-02-17 06:17:40 -06:00
|
|
|
bcx: block,
|
2012-01-19 12:37:40 -06:00
|
|
|
sz: ValueRef,
|
|
|
|
align: ValueRef
|
|
|
|
};
|
|
|
|
|
|
|
|
type tag_metrics = {
|
2012-02-17 06:17:40 -06:00
|
|
|
bcx: block,
|
2012-01-19 12:37:40 -06:00
|
|
|
sz: ValueRef,
|
|
|
|
align: ValueRef,
|
|
|
|
payload_align: ValueRef
|
|
|
|
};
|
|
|
|
|
2012-06-11 20:33:58 -05:00
|
|
|
// Returns the number of bytes clobbered by a Store to this type.
|
|
|
|
fn llsize_of_store(cx: @crate_ctxt, t: TypeRef) -> uint {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint;
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
|
2012-06-11 20:33:58 -05:00
|
|
|
// Returns the number of bytes between successive elements of type T in an
|
|
|
|
// array of T. This is the "ABI" size. It includes any ABI-mandated padding.
|
2012-05-02 20:33:57 -05:00
|
|
|
fn llsize_of_alloc(cx: @crate_ctxt, t: TypeRef) -> uint {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMABISizeOfType(cx.td.lltd, t) as uint;
|
2012-05-02 20:33:57 -05:00
|
|
|
}
|
|
|
|
|
2012-06-11 20:33:58 -05:00
|
|
|
// Returns, as near as we can figure, the "real" size of a type. As in, the
|
|
|
|
// bits in this number of bytes actually carry data related to the datum
|
|
|
|
// with the type. Not junk, padding, accidentally-damaged words, or
|
|
|
|
// whatever. Rounds up to the nearest byte though, so if you have a 1-bit
|
|
|
|
// value, we return 1 here, not 0. Most of rustc works in bytes.
|
|
|
|
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
|
|
|
|
let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, t) as uint;
|
|
|
|
if nbits & 7u != 0u {
|
|
|
|
// Not an even number of bytes, spills into "next" byte.
|
|
|
|
1u + (nbits >> 3)
|
|
|
|
} else {
|
|
|
|
nbits >> 3
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the "default" size of t, which is calculated by casting null to a
|
|
|
|
// *T and then doing gep(1) on it and measuring the result. Really, look in
|
|
|
|
// the LLVM sources. It does that. So this is likely similar to the ABI size
|
|
|
|
// (i.e. including alignment-padding), but goodness knows which alignment it
|
|
|
|
// winds up using. Probably the ABI one? Not recommended.
|
|
|
|
fn llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), cx.int_type,
|
2012-06-11 20:33:58 -05:00
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
2012-04-26 23:44:27 -05:00
|
|
|
// Returns the preferred alignment of the given type for the current target.
|
|
|
|
// The preffered alignment may be larger than the alignment used when
|
2012-06-11 20:33:58 -05:00
|
|
|
// packing the type into structs. This will be used for things like
|
|
|
|
// allocations inside a stack frame, which LLVM has a free hand in.
|
2012-04-26 23:44:27 -05:00
|
|
|
fn llalign_of_pref(cx: @crate_ctxt, t: TypeRef) -> uint {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint;
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
|
2012-04-26 23:52:55 -05:00
|
|
|
// Returns the minimum alignment of a type required by the plattform.
|
2012-06-11 20:33:58 -05:00
|
|
|
// This is the alignment that will be used for struct fields, arrays,
|
|
|
|
// and similar ABI-mandated things.
|
2012-04-26 23:52:55 -05:00
|
|
|
fn llalign_of_min(cx: @crate_ctxt, t: TypeRef) -> uint {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMABIAlignmentOfType(cx.td.lltd, t) as uint;
|
2012-04-26 23:52:55 -05:00
|
|
|
}
|
|
|
|
|
2012-06-11 20:33:58 -05:00
|
|
|
// Returns the "default" alignment of t, which is calculated by casting
|
|
|
|
// null to a record containing a single-bit followed by a t value, then
|
|
|
|
// doing gep(0,1) to get at the trailing (and presumably padded) t cell.
|
2012-03-14 19:31:16 -05:00
|
|
|
fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
2012-08-01 19:30:05 -05:00
|
|
|
return llvm::LLVMConstIntCast(
|
|
|
|
lib::llvm::llvm::LLVMAlignOf(t), cx.int_type, False);
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
|
2012-02-21 07:25:53 -06:00
|
|
|
// Computes the static size of a enum, without using mk_tup(), which is
|
|
|
|
// bad for performance.
|
|
|
|
//
|
2012-06-21 18:44:10 -05:00
|
|
|
// NB: Migrate trans over to use this.
|
2012-02-21 07:25:53 -06:00
|
|
|
|
2012-03-12 04:05:15 -05:00
|
|
|
// Computes the size of the data part of an enum.
|
2012-03-14 19:31:16 -05:00
|
|
|
fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) -> uint {
|
2012-08-01 19:30:05 -05:00
|
|
|
if cx.enum_sizes.contains_key(t) { return cx.enum_sizes.get(t); }
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty::get(t).struct {
|
2012-08-10 12:49:31 -05:00
|
|
|
ty::ty_enum(tid, ref substs) => {
|
2012-01-19 12:21:42 -06:00
|
|
|
// Compute max(variant sizes).
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut max_size = 0u;
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(cx.tcx, tid);
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(*variants) |variant| {
|
2012-02-13 07:10:03 -06:00
|
|
|
let tup_ty = simplify_type(cx.tcx,
|
|
|
|
ty::mk_tup(cx.tcx, variant.args));
|
2012-01-19 12:21:42 -06:00
|
|
|
// Perform any type parameter substitutions.
|
2012-04-18 23:26:25 -05:00
|
|
|
let tup_ty = ty::subst(cx.tcx, substs, tup_ty);
|
2012-01-19 12:21:42 -06:00
|
|
|
// Here we possibly do a recursive call.
|
2012-01-19 23:15:32 -06:00
|
|
|
let this_size =
|
2012-02-21 08:22:55 -06:00
|
|
|
llsize_of_real(cx, type_of::type_of(cx, tup_ty));
|
2012-01-19 12:21:42 -06:00
|
|
|
if max_size < this_size { max_size = this_size; }
|
|
|
|
}
|
2012-01-25 07:34:31 -06:00
|
|
|
cx.enum_sizes.insert(t, max_size);
|
2012-08-01 19:30:05 -05:00
|
|
|
return max_size;
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => cx.sess.bug(~"static_size_of_enum called on non-enum")
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2012-02-13 07:10:03 -06:00
|
|
|
// 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.
|
|
|
|
fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
|
|
|
|
fn nilptr(tcx: ty::ctxt) -> ty::t {
|
2012-02-15 13:25:39 -06:00
|
|
|
ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mutbl: ast::m_imm})
|
2012-02-13 07:10:03 -06:00
|
|
|
}
|
|
|
|
fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t {
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty::get(typ).struct {
|
2012-07-14 14:19:36 -05:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) |
|
2012-04-09 19:32:49 -05:00
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
|
|
|
|
ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_ptr(_) | ty::ty_rptr(_,_) => nilptr(tcx),
|
|
|
|
ty::ty_fn(_) => ty::mk_tup(tcx, ~[nilptr(tcx), nilptr(tcx)]),
|
2012-04-09 19:32:49 -05:00
|
|
|
ty::ty_evec(_, ty::vstore_slice(_)) |
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_estr(ty::vstore_slice(_)) => {
|
2012-06-29 18:26:56 -05:00
|
|
|
ty::mk_tup(tcx, ~[nilptr(tcx), ty::mk_int(tcx)])
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
2012-06-26 00:11:19 -05:00
|
|
|
// Reduce a class type to a record type in which all the fields are
|
|
|
|
// simplified
|
2012-08-10 12:49:31 -05:00
|
|
|
ty::ty_class(did, ref substs) => {
|
2012-06-26 00:11:19 -05:00
|
|
|
let simpl_fields = (if is_some(ty::ty_dtor(tcx, did)) {
|
|
|
|
// remember the drop flag
|
2012-07-18 18:18:02 -05:00
|
|
|
~[{ident: syntax::parse::token::special_idents::dtor,
|
|
|
|
mt: {ty: ty::mk_u8(tcx),
|
|
|
|
mutbl: ast::m_mutbl}}] }
|
2012-06-29 18:26:56 -05:00
|
|
|
else { ~[] }) +
|
2012-06-30 18:19:07 -05:00
|
|
|
do ty::lookup_class_fields(tcx, did).map |f| {
|
2012-06-26 00:11:19 -05:00
|
|
|
let t = ty::lookup_field_type(tcx, did, f.id, substs);
|
|
|
|
{ident: f.ident,
|
|
|
|
mt: {ty: simplify_type(tcx, t), mutbl: ast::m_const}}
|
|
|
|
};
|
|
|
|
ty::mk_rec(tcx, simpl_fields)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => typ
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
}
|
2012-06-30 18:19:07 -05:00
|
|
|
ty::fold_ty(tcx, typ, |t| simplifier(tcx, t))
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|