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-01-19 12:21:42 -06:00
|
|
|
import lib::llvm::llvm;
|
2012-02-01 04:04:56 -06:00
|
|
|
import lib::llvm::{True, False, ModuleRef, TypeRef, ValueRef};
|
2011-11-14 21:37:35 -06:00
|
|
|
import driver::session;
|
2012-01-19 12:21:42 -06:00
|
|
|
import driver::session::session;
|
2012-01-27 06:17:06 -06:00
|
|
|
import trans::base;
|
|
|
|
import middle::trans::common::{crate_ctxt, val_ty, C_bytes, C_int,
|
|
|
|
C_named_struct, C_struct, T_enum_variant,
|
|
|
|
block_ctxt, result, rslt, bcx_ccx, bcx_tcx,
|
|
|
|
type_has_static_size, umax, umin, align_to,
|
|
|
|
tydesc_info};
|
2012-01-19 12:21:42 -06:00
|
|
|
import back::abi;
|
2011-08-04 12:46:10 -05:00
|
|
|
import middle::ty;
|
2011-11-10 10:41:42 -06:00
|
|
|
import middle::ty::field;
|
2011-08-04 12:46:10 -05:00
|
|
|
import syntax::ast;
|
2011-08-21 23:44:41 -05:00
|
|
|
import syntax::ast_util::dummy_sp;
|
2011-08-04 12:46:10 -05:00
|
|
|
import syntax::util::interner;
|
|
|
|
import util::common;
|
2012-01-27 06:17:06 -06:00
|
|
|
import trans::build::{Load, Store, Add, GEPi};
|
2012-01-19 12:21:42 -06:00
|
|
|
import syntax::codemap::span;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-12-13 18:25:51 -06:00
|
|
|
import core::{vec, str};
|
2011-08-04 12:46:10 -05:00
|
|
|
import std::map::hashmap;
|
2011-12-13 18:25:51 -06:00
|
|
|
import option::{none, some};
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
import ty_ctxt = middle::ty::ctxt;
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
type res_info = {did: ast::def_id, t: ty::t};
|
|
|
|
|
|
|
|
type ctxt =
|
|
|
|
{mutable next_tag_id: u16,
|
|
|
|
pad: u16,
|
|
|
|
tag_id_to_index: hashmap<ast::def_id, u16>,
|
|
|
|
mutable tag_order: [ast::def_id],
|
|
|
|
resources: interner::interner<res_info>,
|
|
|
|
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;
|
2011-09-02 08:32:37 -05:00
|
|
|
// (10 is currently unused, was evec)
|
2011-09-02 09:09:41 -05:00
|
|
|
const shape_vec: u8 = 11u8;
|
2012-01-25 07:34:31 -06:00
|
|
|
const shape_enum: u8 = 12u8;
|
2011-08-19 17:16:48 -05:00
|
|
|
const shape_box: u8 = 13u8;
|
|
|
|
const shape_struct: u8 = 17u8;
|
2012-01-11 23:31:36 -06:00
|
|
|
const shape_box_fn: u8 = 18u8;
|
2012-01-13 03:58:31 -06:00
|
|
|
const shape_UNUSED: u8 = 19u8;
|
2011-08-19 17:16:48 -05:00
|
|
|
const shape_res: u8 = 20u8;
|
|
|
|
const shape_var: u8 = 21u8;
|
|
|
|
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-07 15:44:14 -06:00
|
|
|
const shape_iface: u8 = 24u8;
|
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;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
// FIXME: This is a bad API in trans_common.
|
2012-01-27 06:17:06 -06:00
|
|
|
fn C_u8(n: u8) -> ValueRef { ret trans::common::C_u8(n as uint); }
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn hash_res_info(ri: res_info) -> uint {
|
2011-08-04 12:46:10 -05:00
|
|
|
let h = 5381u;
|
2011-08-19 17:16:48 -05:00
|
|
|
h *= 33u;
|
|
|
|
h += ri.did.crate as uint;
|
|
|
|
h *= 33u;
|
|
|
|
h += ri.did.node as uint;
|
|
|
|
h *= 33u;
|
|
|
|
h += ri.t as uint;
|
2011-08-04 12:46:10 -05:00
|
|
|
ret h;
|
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn eq_res_info(a: res_info, b: res_info) -> bool {
|
2011-08-04 12:46:10 -05:00
|
|
|
ret a.did.crate == b.did.crate && a.did.node == b.did.node && a.t == b.t;
|
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -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 =
|
|
|
|
str::as_buf(name,
|
|
|
|
{|buf|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2011-08-04 12:46:10 -05:00
|
|
|
ret llglobal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
//
|
|
|
|
// TODO: Use this in dynamic_size_of() as well.
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn largest_variants(ccx: @crate_ctxt, tag_id: ast::def_id) -> [uint] {
|
2011-08-04 12:46:10 -05:00
|
|
|
// Compute the minimum and maximum size and alignment for each variant.
|
|
|
|
//
|
|
|
|
// TODO: We could do better here; e.g. we know that any variant that
|
|
|
|
// contains (T,T) must be as least as large as any variant that contains
|
|
|
|
// just T.
|
2011-08-19 17:16:48 -05:00
|
|
|
let ranges = [];
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, tag_id);
|
2011-12-15 19:14:58 -06:00
|
|
|
for variant: ty::variant_info in *variants {
|
2011-08-04 12:46:10 -05:00
|
|
|
let bounded = true;
|
2011-08-19 17:16:48 -05:00
|
|
|
let {a: min_size, b: min_align} = {a: 0u, b: 0u};
|
|
|
|
for elem_t: ty::t in variant.args {
|
2011-08-04 12:46:10 -05:00
|
|
|
if ty::type_contains_params(ccx.tcx, elem_t) {
|
|
|
|
// TODO: We could do better here; this causes us to
|
|
|
|
// conservatively assume that (int, T) has minimum size 0,
|
|
|
|
// when in fact it has minimum size sizeof(int).
|
|
|
|
bounded = false;
|
|
|
|
} else {
|
2011-09-02 20:59:22 -05:00
|
|
|
// Could avoid this check: the constraint should
|
|
|
|
// follow from how elem_t doesn't contain params.
|
|
|
|
// (Could add a postcondition to type_contains_params,
|
|
|
|
// once we implement Issue #586.)
|
2012-01-27 06:17:06 -06:00
|
|
|
check (trans::common::type_has_static_size(ccx, elem_t));
|
|
|
|
let llty = base::type_of(ccx, elem_t);
|
2012-01-19 12:21:42 -06:00
|
|
|
min_size += llsize_of_real(ccx, llty);
|
|
|
|
min_align += llalign_of_real(ccx, llty);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
ranges +=
|
|
|
|
[{size: {min: min_size, bounded: bounded},
|
|
|
|
align: {min: min_align, bounded: bounded}}];
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the candidate set to contain all variants.
|
2011-08-19 17:16:48 -05:00
|
|
|
let candidates = [mutable];
|
2011-12-15 19:14:58 -06:00
|
|
|
for variant in *variants { candidates += [mutable true]; }
|
2011-08-04 12:46:10 -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 i = 0u;
|
2011-08-15 18:38:23 -05:00
|
|
|
while i < vec::len(ranges) - 1u {
|
2011-08-19 17:16:48 -05:00
|
|
|
if candidates[i] {
|
2011-08-04 12:46:10 -05:00
|
|
|
let j = i + 1u;
|
2011-08-19 17:16:48 -05:00
|
|
|
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 {
|
|
|
|
if ranges[i].size >= ranges[j].size &&
|
|
|
|
ranges[i].align >= ranges[j].align {
|
2011-08-04 12:46:10 -05:00
|
|
|
// Throw out j.
|
2011-08-19 17:16:48 -05:00
|
|
|
candidates[j] = false;
|
|
|
|
} else if ranges[j].size >= ranges[i].size &&
|
|
|
|
ranges[j].align >= ranges[j].align {
|
2011-08-04 12:46:10 -05:00
|
|
|
// Throw out i.
|
2011-08-19 17:16:48 -05:00
|
|
|
candidates[i] = false;
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the resulting set.
|
2011-08-19 17:16:48 -05:00
|
|
|
let result = [];
|
2011-08-04 12:46:10 -05:00
|
|
|
i = 0u;
|
2011-08-15 18:38:23 -05:00
|
|
|
while i < vec::len(candidates) {
|
2011-08-19 17:16:48 -05:00
|
|
|
if candidates[i] { result += [i]; }
|
2011-08-04 12:46:10 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
// Computes the static size of a enum, without using mk_tup(), which is
|
2011-08-04 12:46:10 -05:00
|
|
|
// bad for performance.
|
|
|
|
//
|
|
|
|
// TODO: Migrate trans over to use this.
|
|
|
|
|
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;
|
2011-08-19 17:16:48 -05:00
|
|
|
ret 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
|
|
|
fn compute_static_enum_size(ccx: @crate_ctxt, largest_variants: [uint],
|
2011-09-12 04:27:30 -05:00
|
|
|
did: ast::def_id) -> size_align {
|
2011-08-19 17:16:48 -05:00
|
|
|
let max_size = 0u16;
|
|
|
|
let max_align = 1u8;
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2011-08-19 17:16:48 -05:00
|
|
|
for vid: uint in largest_variants {
|
2011-08-04 12:46:10 -05:00
|
|
|
// We increment a "virtual data pointer" to compute the size.
|
2011-08-19 17:16:48 -05:00
|
|
|
let lltys = [];
|
|
|
|
for typ: ty::t in variants[vid].args {
|
2011-09-02 20:59:22 -05:00
|
|
|
// FIXME: there should really be a postcondition
|
2012-01-25 07:34:31 -06:00
|
|
|
// on enum_variants that would obviate the need for
|
2011-09-02 20:59:22 -05:00
|
|
|
// this check. (Issue #586)
|
2012-01-27 06:17:06 -06:00
|
|
|
check (trans::common::type_has_static_size(ccx, typ));
|
|
|
|
lltys += [base::type_of(ccx, typ)];
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2012-01-27 06:17:06 -06:00
|
|
|
let llty = trans::common::T_struct(lltys);
|
2012-01-19 12:21:42 -06:00
|
|
|
let dp = llsize_of_real(ccx, llty) as u16;
|
|
|
|
let variant_align = llalign_of_real(ccx, llty) as u8;
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
if max_size < dp { max_size = dp; }
|
|
|
|
if max_align < variant_align { max_align = variant_align; }
|
|
|
|
}
|
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
// Add space for the enum if applicable.
|
|
|
|
// FIXME (issue #792): This is wrong. If the enum starts with an 8 byte
|
2011-08-04 12:46:10 -05:00
|
|
|
// aligned quantity, we don't align it.
|
2011-12-15 19:14:58 -06:00
|
|
|
if vec::len(*variants) > 1u {
|
2012-01-25 07:34:31 -06:00
|
|
|
let variant_t = T_enum_variant(ccx);
|
2012-01-19 12:21:42 -06:00
|
|
|
max_size += llsize_of_real(ccx, variant_t) as u16;
|
|
|
|
let align = llalign_of_real(ccx, variant_t) as u8;
|
2011-11-23 14:01:15 -06:00
|
|
|
if max_align < align { max_align = align; }
|
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
ret {size: max_size, align: max_align};
|
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-01-25 07:34:31 -06:00
|
|
|
fn enum_kind(ccx: @crate_ctxt, did: ast::def_id) -> enum_kind {
|
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2012-01-19 12:37:40 -06:00
|
|
|
if vec::any(*variants) {|v| vec::len(v.args) > 0u} {
|
|
|
|
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-01-12 10:59:49 -06:00
|
|
|
ret alt tcx.sess.targ_cfg.arch {
|
2012-01-19 03:03:57 -06: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-01-12 10:59:49 -06:00
|
|
|
ret alt tcx.sess.targ_cfg.arch {
|
2012-01-19 03:03:57 -06: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-01-12 10:59:49 -06:00
|
|
|
ret alt tcx.sess.targ_cfg.arch {
|
2012-01-19 03:03:57 -06: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 {
|
2011-11-14 21:37:35 -06:00
|
|
|
ret 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 {
|
|
|
|
ret shape_tydesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn s_send_tydesc(_tcx: ty_ctxt) -> u8 {
|
|
|
|
ret shape_send_tydesc;
|
|
|
|
}
|
|
|
|
|
2011-10-12 15:31:41 -05:00
|
|
|
fn mk_ctxt(llmod: ModuleRef) -> ctxt {
|
2012-01-27 06:17:06 -06:00
|
|
|
let llshapetablesty = trans::common::T_named_struct("shapes");
|
|
|
|
let llshapetables = str::as_buf("shapes", {|buf|
|
|
|
|
lib::llvm::llvm::LLVMAddGlobal(llmod, llshapetablesty, buf)
|
|
|
|
});
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
ret {mutable next_tag_id: 0u16,
|
|
|
|
pad: 0u16,
|
|
|
|
tag_id_to_index: common::new_def_hash(),
|
|
|
|
mutable tag_order: [],
|
|
|
|
resources: interner::mk(hash_res_info, eq_res_info),
|
|
|
|
llshapetablesty: llshapetablesty,
|
|
|
|
llshapetables: llshapetables};
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-09-12 05:39:38 -05:00
|
|
|
fn add_bool(&dest: [u8], val: bool) { dest += [if val { 1u8 } else { 0u8 }]; }
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-09-12 05:39:38 -05:00
|
|
|
fn add_u16(&dest: [u8], val: u16) {
|
2011-08-19 17:16:48 -05:00
|
|
|
dest += [val & 0xffu16 as u8, val >> 8u16 as u8];
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-09-12 05:39:38 -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-01-13 03:58:31 -06:00
|
|
|
fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
2011-08-19 17:16:48 -05:00
|
|
|
let s = [];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
alt ty::struct(ccx.tcx, t) {
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_nil | ty::ty_bool | ty::ty_uint(ast::ty_u8) |
|
|
|
|
ty::ty_bot { s += [shape_u8]; }
|
|
|
|
ty::ty_int(ast::ty_i) { s += [s_int(ccx.tcx)]; }
|
|
|
|
ty::ty_float(ast::ty_f) { s += [s_float(ccx.tcx)]; }
|
2012-02-01 04:54:14 -06:00
|
|
|
ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) { s += [s_uint(ccx.tcx)]; }
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_type { s += [s_tydesc(ccx.tcx)]; }
|
|
|
|
ty::ty_send_type { s += [s_send_tydesc(ccx.tcx)]; }
|
|
|
|
ty::ty_int(ast::ty_i8) { s += [shape_i8]; }
|
|
|
|
ty::ty_uint(ast::ty_u16) { s += [shape_u16]; }
|
|
|
|
ty::ty_int(ast::ty_i16) { s += [shape_i16]; }
|
|
|
|
ty::ty_uint(ast::ty_u32) { s += [shape_u32]; }
|
|
|
|
ty::ty_int(ast::ty_i32) | ty::ty_int(ast::ty_char) {s += [shape_i32];}
|
|
|
|
ty::ty_uint(ast::ty_u64) { s += [shape_u64]; }
|
|
|
|
ty::ty_int(ast::ty_i64) { s += [shape_i64]; }
|
|
|
|
ty::ty_float(ast::ty_f32) { s += [shape_f32]; }
|
|
|
|
ty::ty_float(ast::ty_f64) { s += [shape_f64]; }
|
|
|
|
ty::ty_str {
|
2011-09-02 09:09:41 -05:00
|
|
|
s += [shape_vec];
|
2011-08-22 18:12:42 -05:00
|
|
|
add_bool(s, true); // type is POD
|
2011-12-07 14:06:12 -06:00
|
|
|
let unit_ty = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, unit_ty, ty_param_map));
|
2011-08-22 18:12:42 -05:00
|
|
|
}
|
2012-01-25 07:34:31 -06:00
|
|
|
ty::ty_enum(did, tps) {
|
|
|
|
alt enum_kind(ccx, did) {
|
2012-01-19 00:37:22 -06:00
|
|
|
tk_unit {
|
2011-08-04 12:46:10 -05:00
|
|
|
// FIXME: For now we do this.
|
2012-01-25 07:34:31 -06:00
|
|
|
s += [s_variant_enum_t(ccx.tcx)];
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2012-01-25 07:34:31 -06:00
|
|
|
tk_enum { s += [s_variant_enum_t(ccx.tcx)]; }
|
2012-01-19 12:37:40 -06:00
|
|
|
tk_newtype | tk_complex {
|
2012-01-25 07:34:31 -06:00
|
|
|
s += [shape_enum];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
let sub = [];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
let id;
|
|
|
|
alt ccx.shape_cx.tag_id_to_index.find(did) {
|
2012-01-19 00:37:22 -06:00
|
|
|
none {
|
2011-08-04 12:46:10 -05:00
|
|
|
id = ccx.shape_cx.next_tag_id;
|
|
|
|
ccx.shape_cx.tag_id_to_index.insert(did, id);
|
2011-08-19 17:16:48 -05:00
|
|
|
ccx.shape_cx.tag_order += [did];
|
2011-08-04 12:46:10 -05:00
|
|
|
ccx.shape_cx.next_tag_id += 1u16;
|
|
|
|
}
|
|
|
|
some(existing_id) { id = existing_id; }
|
|
|
|
}
|
|
|
|
add_u16(sub, id as u16);
|
|
|
|
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(sub, vec::len(tps) as u16);
|
2011-08-19 17:16:48 -05:00
|
|
|
for tp: ty::t in tps {
|
2012-01-13 03:58:31 -06:00
|
|
|
let subshape = shape_of(ccx, tp, ty_param_map);
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(sub, vec::len(subshape) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
sub += subshape;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += sub;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_box(mt) {
|
2011-08-19 17:16:48 -05:00
|
|
|
s += [shape_box];
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
2011-09-21 20:54:54 -05:00
|
|
|
ty::ty_uniq(mt) {
|
2011-08-19 17:16:48 -05:00
|
|
|
s += [shape_uniq];
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
2011-08-10 19:23:46 -05:00
|
|
|
}
|
2011-08-18 16:11:06 -05:00
|
|
|
ty::ty_vec(mt) {
|
2011-09-02 09:09:41 -05:00
|
|
|
s += [shape_vec];
|
2011-08-04 12:46:10 -05:00
|
|
|
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
ty::ty_rec(fields) {
|
2011-08-19 17:16:48 -05:00
|
|
|
s += [shape_struct];
|
|
|
|
let sub = [];
|
2011-09-02 12:16:41 -05:00
|
|
|
for f: field in fields {
|
2012-01-13 03:58:31 -06:00
|
|
|
sub += shape_of(ccx, f.mt.ty, ty_param_map);
|
2011-09-02 12:16:41 -05:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
add_substr(s, sub);
|
|
|
|
}
|
2011-08-15 04:40:26 -05:00
|
|
|
ty::ty_tup(elts) {
|
2011-08-19 17:16:48 -05:00
|
|
|
s += [shape_struct];
|
|
|
|
let sub = [];
|
2011-09-22 18:10:48 -05:00
|
|
|
for elt in elts {
|
2012-01-13 03:58:31 -06:00
|
|
|
sub += shape_of(ccx, elt, ty_param_map);
|
2011-09-22 18:10:48 -05:00
|
|
|
}
|
2011-08-15 04:40:26 -05:00
|
|
|
add_substr(s, sub);
|
|
|
|
}
|
2012-01-07 15:44:14 -06:00
|
|
|
ty::ty_iface(_, _) { s += [shape_iface]; }
|
2011-08-04 12:46:10 -05:00
|
|
|
ty::ty_res(did, raw_subt, tps) {
|
|
|
|
let subt = ty::substitute_type_params(ccx.tcx, tps, raw_subt);
|
2011-08-19 17:16:48 -05:00
|
|
|
let ri = {did: did, t: subt};
|
2011-08-04 12:46:10 -05:00
|
|
|
let id = interner::intern(ccx.shape_cx.resources, ri);
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
s += [shape_res];
|
2011-08-04 12:46:10 -05:00
|
|
|
add_u16(s, id as u16);
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(s, vec::len(tps) as u16);
|
2011-09-02 12:16:41 -05:00
|
|
|
for tp: ty::t in tps {
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, tp, ty_param_map));
|
2011-09-02 12:16:41 -05:00
|
|
|
}
|
2012-01-13 03:58:31 -06:00
|
|
|
add_substr(s, shape_of(ccx, subt, ty_param_map));
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
}
|
2011-09-02 12:16:41 -05:00
|
|
|
ty::ty_param(n, _) {
|
2012-01-13 03:58:31 -06:00
|
|
|
// Find the type parameter in the parameter list.
|
2012-01-26 10:39:45 -06:00
|
|
|
alt vec::position_elt(ty_param_map, n) {
|
2012-01-13 03:58:31 -06:00
|
|
|
some(i) { s += [shape_var, i as u8]; }
|
2012-01-19 00:37:22 -06:00
|
|
|
none { fail "ty param not found in ty_param_map"; }
|
2011-09-02 12:16:41 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_fn({proto: ast::proto_box, _}) {
|
2012-01-11 23:31:36 -06:00
|
|
|
s += [shape_box_fn];
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_fn({proto: ast::proto_uniq, _}) {
|
2012-01-11 23:31:36 -06:00
|
|
|
s += [shape_uniq_fn];
|
|
|
|
}
|
2012-01-18 14:04:07 -06:00
|
|
|
ty::ty_fn({proto: ast::proto_block, _}) |
|
|
|
|
ty::ty_fn({proto: ast::proto_any, _}) {
|
2012-01-11 23:31:36 -06:00
|
|
|
s += [shape_stack_fn];
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_fn({proto: ast::proto_bare, _}) {
|
2012-01-11 23:31:36 -06:00
|
|
|
s += [shape_bare_fn];
|
2011-12-15 13:06:48 -06:00
|
|
|
}
|
2012-01-05 18:19:12 -06:00
|
|
|
ty::ty_opaque_closure_ptr(_) {
|
|
|
|
s += [shape_opaque_closure_ptr];
|
2011-12-15 13:06:48 -06:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
ty::ty_constr(inner_t, _) {
|
|
|
|
s += shape_of(ccx, inner_t, ty_param_map);
|
|
|
|
}
|
2012-01-30 04:52:34 -06:00
|
|
|
ty::ty_var(_) | ty::ty_named(_, _) | ty::ty_self(_) {
|
|
|
|
ccx.tcx.sess.bug("shape_of: unexpected type struct found");
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ret s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: We might discover other variants as we traverse these. Handle this.
|
2011-09-12 04:27:30 -05:00
|
|
|
fn shape_of_variant(ccx: @crate_ctxt, v: ty::variant_info,
|
2011-09-02 12:16:41 -05:00
|
|
|
ty_param_count: uint) -> [u8] {
|
|
|
|
let ty_param_map = [];
|
|
|
|
let i = 0u;
|
2011-09-02 17:34:58 -05:00
|
|
|
while i < ty_param_count { ty_param_map += [i]; i += 1u; }
|
2011-09-02 12:16:41 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
let s = [];
|
2012-01-13 03:58:31 -06:00
|
|
|
for t: ty::t in v.args { s += shape_of(ccx, t, ty_param_map); }
|
2011-08-04 12:46:10 -05:00
|
|
|
ret s;
|
|
|
|
}
|
|
|
|
|
2012-01-25 07:34:31 -06:00
|
|
|
fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
|
|
|
// 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.
|
2011-08-04 12:46:10 -05:00
|
|
|
let i = 0u;
|
2011-08-19 17:16:48 -05:00
|
|
|
let data = [];
|
|
|
|
let offsets = [];
|
|
|
|
while i < vec::len(ccx.shape_cx.tag_order) {
|
|
|
|
let did = ccx.shape_cx.tag_order[i];
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2011-09-02 12:16:41 -05:00
|
|
|
let item_tyt = ty::lookup_item_type(ccx.tcx, did);
|
2012-01-02 05:09:26 -06:00
|
|
|
let ty_param_count = vec::len(*item_tyt.bounds);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2012-01-15 23:42:10 -06:00
|
|
|
vec::iter(*variants) {|v|
|
2011-08-19 17:16:48 -05:00
|
|
|
offsets += [vec::len(data) as u16];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
2011-09-02 12:16:41 -05:00
|
|
|
let variant_shape = shape_of_variant(ccx, v, ty_param_count);
|
2011-08-04 12:46:10 -05:00
|
|
|
add_substr(data, variant_shape);
|
2012-01-15 23:42:10 -06:00
|
|
|
|
|
|
|
let zname = str::bytes(v.name) + [0u8];
|
|
|
|
add_substr(data, zname);
|
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.
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
let header = [];
|
|
|
|
let info = [];
|
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
|
|
|
|
|
|
|
let info_sz = 0u16;
|
2011-08-19 17:16:48 -05:00
|
|
|
for did_: ast::def_id in ccx.shape_cx.tag_order {
|
|
|
|
let did = did_; // Satisfy alias checker.
|
2012-01-25 07:34:31 -06:00
|
|
|
let num_variants = vec::len(*ty::enum_variants(ccx.tcx, did)) as u16;
|
2011-08-04 12:46:10 -05:00
|
|
|
add_u16(header, header_sz + info_sz);
|
2012-01-17 22:59:49 -06:00
|
|
|
info_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.
|
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
let lv_table = [];
|
2011-08-04 12:46:10 -05:00
|
|
|
i = 0u;
|
2011-08-19 17:16:48 -05:00
|
|
|
for did_: ast::def_id in ccx.shape_cx.tag_order {
|
|
|
|
let did = did_; // Satisfy alias checker.
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2011-12-15 19:14:58 -06:00
|
|
|
add_u16(info, vec::len(*variants) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
// Construct the largest-variants table.
|
2011-08-19 17:16:48 -05:00
|
|
|
add_u16(info,
|
|
|
|
header_sz + info_sz + data_sz + (vec::len(lv_table) as u16));
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
let lv = largest_variants(ccx, did);
|
2011-08-15 18:38:23 -05:00
|
|
|
add_u16(lv_table, vec::len(lv) as u16);
|
2011-08-19 17:16:48 -05:00
|
|
|
for v: uint in lv { 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.
|
2011-08-04 12:46:10 -05:00
|
|
|
let dynamic = false;
|
2011-12-15 19:14:58 -06:00
|
|
|
for variant: ty::variant_info in *variants {
|
2011-08-19 17:16:48 -05:00
|
|
|
for typ: ty::t in variant.args {
|
2011-08-04 12:46:10 -05:00
|
|
|
if ty::type_has_dynamic_size(ccx.tcx, typ) { dynamic = true; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
let size_align;
|
|
|
|
if dynamic {
|
2011-08-19 17:16:48 -05:00
|
|
|
size_align = {size: 0u16, align: 0u8};
|
2012-01-25 07:34:31 -06:00
|
|
|
} else { size_align = compute_static_enum_size(ccx, lv, did); }
|
2011-08-04 12:46:10 -05:00
|
|
|
add_u16(info, size_align.size);
|
2011-08-19 17:16:48 -05:00
|
|
|
info += [size_align.align];
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
// Now write in the offset of each variant.
|
2011-12-15 19:14:58 -06:00
|
|
|
for v: ty::variant_info in *variants {
|
2011-08-19 17:16:48 -05:00
|
|
|
add_u16(info, header_sz + info_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);
|
|
|
|
assert (info_sz == vec::len(info) as u16);
|
|
|
|
assert (data_sz == vec::len(data) as u16);
|
2011-08-04 12:46:10 -05:00
|
|
|
|
|
|
|
header += info;
|
|
|
|
header += data;
|
|
|
|
header += lv_table;
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
ret mk_global(ccx, "tag_shapes", C_bytes(header), true);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
|
2011-08-19 17:16:48 -05:00
|
|
|
let dtors = [];
|
2011-08-04 12:46:10 -05:00
|
|
|
let i = 0u;
|
|
|
|
let len = interner::len(ccx.shape_cx.resources);
|
|
|
|
while i < len {
|
|
|
|
let ri = interner::get(ccx.shape_cx.resources, i);
|
2012-01-27 06:17:06 -06:00
|
|
|
dtors += [trans::common::get_res_dtor(ccx, ri.did, ri.t)];
|
2011-08-04 12:46:10 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
ret mk_global(ccx, "resource_shapes", C_struct(dtors), true);
|
2011-08-04 12:46:10 -05:00
|
|
|
}
|
|
|
|
|
2011-10-12 15:31:41 -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,
|
|
|
|
[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,
|
|
|
|
[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 = {
|
|
|
|
bcx: @block_ctxt,
|
|
|
|
sz: ValueRef,
|
|
|
|
align: ValueRef
|
|
|
|
};
|
|
|
|
|
|
|
|
type tag_metrics = {
|
|
|
|
bcx: @block_ctxt,
|
|
|
|
sz: ValueRef,
|
|
|
|
align: ValueRef,
|
|
|
|
payload_align: ValueRef
|
|
|
|
};
|
|
|
|
|
|
|
|
fn size_of(bcx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
if check type_has_static_size(ccx, t) {
|
2012-01-27 06:17:06 -06:00
|
|
|
rslt(bcx, llsize_of(ccx, base::type_of(ccx, t)))
|
2012-01-19 12:37:40 -06:00
|
|
|
} else {
|
|
|
|
let { bcx, sz, align: _ } = dynamic_metrics(bcx, t);
|
|
|
|
rslt(bcx, sz)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
let ccx = bcx_ccx(bcx);
|
2012-01-19 12:21:42 -06:00
|
|
|
if check type_has_static_size(ccx, t) {
|
2012-01-27 06:17:06 -06:00
|
|
|
rslt(bcx, llalign_of(ccx, base::type_of(ccx, t)))
|
2012-01-19 12:37:40 -06:00
|
|
|
} else {
|
|
|
|
let { bcx, sz: _, align } = dynamic_metrics(bcx, t);
|
|
|
|
rslt(bcx, align)
|
|
|
|
}
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
|
2012-01-19 12:37:40 -06:00
|
|
|
fn metrics(bcx: @block_ctxt, t: ty::t) -> metrics {
|
|
|
|
let ccx = bcx_ccx(bcx);
|
2012-01-19 12:21:42 -06:00
|
|
|
if check type_has_static_size(ccx, t) {
|
2012-01-27 06:17:06 -06:00
|
|
|
let llty = base::type_of(ccx, t);
|
2012-01-19 12:37:40 -06:00
|
|
|
{ bcx: bcx, sz: llsize_of(ccx, llty), align: llalign_of(ccx, llty) }
|
|
|
|
} else {
|
|
|
|
dynamic_metrics(bcx, t)
|
|
|
|
}
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the real size of the given type for the current target.
|
|
|
|
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
|
|
|
|
ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the real alignment of the given type for the current target.
|
|
|
|
fn llalign_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
|
|
|
|
ret llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), cx.int_type,
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), cx.int_type,
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Computes the size of the data part of a non-dynamically-sized enum.
|
2012-01-27 05:55:21 -06:00
|
|
|
fn static_size_of_enum(cx: @crate_ctxt, t: ty::t)
|
2012-01-19 12:21:42 -06:00
|
|
|
: type_has_static_size(cx, t) -> uint {
|
2012-01-25 07:34:31 -06:00
|
|
|
if cx.enum_sizes.contains_key(t) { ret cx.enum_sizes.get(t); }
|
2012-01-19 12:21:42 -06:00
|
|
|
alt ty::struct(cx.tcx, t) {
|
2012-01-25 07:34:31 -06:00
|
|
|
ty::ty_enum(tid, subtys) {
|
2012-01-19 12:21:42 -06:00
|
|
|
// Compute max(variant sizes).
|
|
|
|
|
|
|
|
let max_size = 0u;
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(cx.tcx, tid);
|
2012-01-19 12:21:42 -06:00
|
|
|
for variant: ty::variant_info in *variants {
|
|
|
|
let tup_ty = simplify_type(cx, ty::mk_tup(cx.tcx, variant.args));
|
|
|
|
// Perform any type parameter substitutions.
|
|
|
|
|
|
|
|
tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
|
|
|
|
// Here we possibly do a recursive call.
|
|
|
|
|
|
|
|
// FIXME: Avoid this check. Since the parent has static
|
|
|
|
// size, any field must as well. There should be a way to
|
|
|
|
// express that with constrained types.
|
|
|
|
check (type_has_static_size(cx, tup_ty));
|
2012-01-19 23:15:32 -06:00
|
|
|
let this_size =
|
2012-01-27 06:17:06 -06:00
|
|
|
llsize_of_real(cx, base::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-01-19 12:21:42 -06:00
|
|
|
ret max_size;
|
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
_ { cx.tcx.sess.bug("static_size_of_enum called on non-enum"); }
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-19 12:37:40 -06:00
|
|
|
fn dynamic_metrics(cx: @block_ctxt, t: ty::t) -> metrics {
|
|
|
|
fn align_elements(cx: @block_ctxt, elts: [ty::t]) -> metrics {
|
2012-01-19 12:21:42 -06:00
|
|
|
//
|
|
|
|
// C padding rules:
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// - Pad after each element so that next element is aligned.
|
|
|
|
// - Pad after final structure member so that whole structure
|
|
|
|
// is aligned to max alignment of interior.
|
|
|
|
//
|
|
|
|
|
|
|
|
let off = C_int(bcx_ccx(cx), 0);
|
|
|
|
let max_align = C_int(bcx_ccx(cx), 1);
|
|
|
|
let bcx = cx;
|
|
|
|
for e: ty::t in elts {
|
|
|
|
let elt_align = align_of(bcx, e);
|
|
|
|
bcx = elt_align.bcx;
|
|
|
|
let elt_size = size_of(bcx, e);
|
|
|
|
bcx = elt_size.bcx;
|
|
|
|
let aligned_off = align_to(bcx, off, elt_align.val);
|
|
|
|
off = Add(bcx, aligned_off, elt_size.val);
|
|
|
|
max_align = umax(bcx, max_align, elt_align.val);
|
|
|
|
}
|
|
|
|
off = align_to(bcx, off, max_align);
|
2012-01-19 12:37:40 -06:00
|
|
|
ret { bcx: bcx, sz: off, align: max_align };
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
2012-01-19 12:37:40 -06:00
|
|
|
|
2012-01-19 12:21:42 -06:00
|
|
|
alt ty::struct(bcx_tcx(cx), t) {
|
|
|
|
ty::ty_param(p, _) {
|
2012-01-19 12:37:40 -06:00
|
|
|
let ti = none::<@tydesc_info>;
|
2012-01-27 06:17:06 -06:00
|
|
|
let {bcx, val: tydesc} = base::get_tydesc(cx, t, false, ti).result;
|
2012-01-19 12:37:40 -06:00
|
|
|
let szptr = GEPi(bcx, tydesc, [0, abi::tydesc_field_size]);
|
|
|
|
let aptr = GEPi(bcx, tydesc, [0, abi::tydesc_field_align]);
|
|
|
|
{bcx: bcx, sz: Load(bcx, szptr), align: Load(bcx, aptr)}
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
ty::ty_rec(flds) {
|
|
|
|
let tys: [ty::t] = [];
|
|
|
|
for f: ty::field in flds { tys += [f.mt.ty]; }
|
2012-01-19 12:37:40 -06:00
|
|
|
align_elements(cx, tys)
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
|
|
|
ty::ty_tup(elts) {
|
|
|
|
let tys = [];
|
|
|
|
for tp in elts { tys += [tp]; }
|
2012-01-19 12:37:40 -06:00
|
|
|
align_elements(cx, tys)
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
2012-01-25 07:34:31 -06:00
|
|
|
ty::ty_enum(tid, tps) {
|
2012-01-19 12:21:42 -06:00
|
|
|
let bcx = cx;
|
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
|
2012-01-19 12:37:40 -06:00
|
|
|
let compute_max_variant_size = fn@(bcx: @block_ctxt) -> result {
|
|
|
|
// Compute max(variant sizes).
|
|
|
|
let bcx = bcx;
|
|
|
|
let max_size: ValueRef = C_int(ccx, 0);
|
2012-01-25 07:34:31 -06:00
|
|
|
let variants = ty::enum_variants(bcx_tcx(bcx), tid);
|
2012-01-19 12:37:40 -06:00
|
|
|
for variant: ty::variant_info in *variants {
|
|
|
|
// Perform type substitution on the raw argument types.
|
|
|
|
let tys = vec::map(variant.args) {|raw_ty|
|
|
|
|
ty::substitute_type_params(bcx_tcx(cx), tps, raw_ty)
|
|
|
|
};
|
|
|
|
let rslt = align_elements(bcx, tys);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
max_size = umax(bcx, rslt.sz, max_size);
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
2012-01-19 12:37:40 -06:00
|
|
|
rslt(bcx, max_size)
|
|
|
|
};
|
2012-01-19 12:21:42 -06:00
|
|
|
|
2012-01-25 07:34:31 -06:00
|
|
|
let {bcx, val: sz} = alt enum_kind(ccx, tid) {
|
|
|
|
tk_unit | tk_enum { rslt(bcx, llsize_of(ccx, T_enum_variant(ccx))) }
|
2012-01-19 12:37:40 -06:00
|
|
|
tk_newtype { compute_max_variant_size(bcx) }
|
|
|
|
tk_complex {
|
|
|
|
let {bcx, val} = compute_max_variant_size(bcx);
|
2012-01-25 07:34:31 -06:00
|
|
|
rslt(bcx, Add(bcx, val, llsize_of(ccx, T_enum_variant(ccx))))
|
2012-01-19 12:37:40 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
{ bcx: bcx, sz: sz, align: C_int(ccx, 1) }
|
2012-01-19 12:21:42 -06:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
_ {
|
|
|
|
// Precondition?
|
|
|
|
bcx_tcx(cx).sess.bug("dynamic_metrics: type has static \
|
|
|
|
size");
|
|
|
|
}
|
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.
|
|
|
|
fn simplify_type(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
|
|
|
|
fn simplifier(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
|
|
|
|
alt ty::struct(ccx.tcx, typ) {
|
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) {
|
|
|
|
ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx));
|
|
|
|
}
|
|
|
|
ty::ty_uniq(_) {
|
|
|
|
ret ty::mk_imm_uniq(ccx.tcx, ty::mk_nil(ccx.tcx));
|
|
|
|
}
|
|
|
|
ty::ty_fn(_) {
|
|
|
|
ret ty::mk_tup(ccx.tcx,
|
|
|
|
[ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
|
|
|
|
ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
|
|
|
|
}
|
|
|
|
ty::ty_res(_, sub, tps) {
|
|
|
|
let sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
|
|
|
|
ret ty::mk_tup(ccx.tcx,
|
|
|
|
[ty::mk_int(ccx.tcx), simplify_type(ccx, sub1)]);
|
|
|
|
}
|
|
|
|
_ { ret typ; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
|
|
|
|
}
|
2012-01-19 12:37:40 -06:00
|
|
|
|
|
|
|
// Given a tag type `ty`, returns the offset of the payload.
|
|
|
|
//fn tag_payload_offs(bcx: @block_ctxt, tag_id: ast::def_id, tps: [ty::t])
|
|
|
|
// -> ValueRef {
|
|
|
|
// alt tag_kind(tag_id) {
|
|
|
|
// tk_unit | tk_enum | tk_newtype { C_int(bcx_ccx(bcx), 0) }
|
|
|
|
// tk_complex {
|
|
|
|
// compute_tag_metrics(tag_id, tps)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|