rustc: Add an extra flag to object tydescs so that shapes know how to find the captured subtydescs

This commit is contained in:
Patrick Walton 2011-08-24 18:36:51 -07:00
parent 2f7c583bc1
commit 880fd788eb
11 changed files with 103 additions and 72 deletions

View file

@ -60,7 +60,8 @@ const tydesc_field_cmp_glue: int = 10;
const tydesc_field_shape: int = 11;
const tydesc_field_shape_tables: int = 12;
const tydesc_field_n_params: int = 13;
const n_tydesc_fields: int = 14;
const tydesc_field_obj_params: int = 14;
const n_tydesc_fields: int = 15;
const cmp_glue_op_eq: uint = 0u;

View file

@ -91,7 +91,7 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
get_type_desc:
d("get_type_desc",
[T_ptr(T_nil()), T_size_t(), T_size_t(), T_size_t(),
T_ptr(T_ptr(tydesc_type))], T_ptr(tydesc_type)),
T_ptr(T_ptr(tydesc_type)), T_int()], T_ptr(tydesc_type)),
ivec_resize:
d("ivec_resize", [T_ptr(T_opaque_ivec()), T_int()], T_void()),
ivec_spill:

View file

@ -4,7 +4,7 @@ import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::llvm::ValueRef;
import middle::trans;
import middle::trans::get_tydesc;
import middle::trans::{ get_tydesc, tps_normal };
import middle::trans_common::*;
import middle::ty;
import std::option::none;
@ -43,7 +43,7 @@ fn add_gc_root(cx: &@block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
bcx = trans::zero_alloca(bcx, llval, ty).bcx;
let ti = none;
let td_r = get_tydesc(bcx, ty, false, ti);
let td_r = get_tydesc(bcx, ty, false, tps_normal, ti);
bcx = td_r.result.bcx;
let lltydesc = td_r.result.val;

View file

@ -884,7 +884,7 @@ fn trans_malloc_boxed(cx: &@block_ctxt, t: ty::t) ->
fn field_of_tydesc(cx: &@block_ctxt, t: ty::t, escapes: bool, field: int) ->
result {
let ti = none::<@tydesc_info>;
let tydesc = get_tydesc(cx, t, escapes, ti).result;
let tydesc = get_tydesc(cx, t, escapes, tps_normal, ti).result;
ret rslt(tydesc.bcx,
bld::GEP(tydesc.bcx, tydesc.val, [C_int(0), C_int(field)]));
}
@ -919,16 +919,16 @@ fn linearize_ty_params(cx: &@block_ctxt, t: ty::t) ->
fn trans_stack_local_derived_tydesc(cx: &@block_ctxt, llsz: ValueRef,
llalign: ValueRef, llroottydesc: ValueRef,
llparamtydescs: ValueRef, n_params: uint)
llfirstparam: ValueRef, n_params: uint,
obj_params: uint)
-> ValueRef {
let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
// By convention, desc 0 is the root descriptor.
// By convention, desc 0 is the root descriptor.
llroottydesc = bld::Load(cx, llroottydesc);
bld::Store(cx, llroottydesc, llmyroottydesc);
// Store a pointer to the rest of the descriptors.
let llfirstparam = bld::GEP(cx, llparamtydescs, [C_int(0), C_int(0)]);
// Store a pointer to the rest of the descriptors.
store_inbounds(cx, llfirstparam, llmyroottydesc,
[C_int(0), C_int(abi::tydesc_field_first_param)]);
store_inbounds(cx, C_uint(n_params), llmyroottydesc,
@ -937,10 +937,20 @@ fn trans_stack_local_derived_tydesc(cx: &@block_ctxt, llsz: ValueRef,
[C_int(0), C_int(abi::tydesc_field_size)]);
store_inbounds(cx, llalign, llmyroottydesc,
[C_int(0), C_int(abi::tydesc_field_align)]);
store_inbounds(cx, C_uint(obj_params), llmyroottydesc,
[C_int(0), C_int(abi::tydesc_field_obj_params)]);
ret llmyroottydesc;
}
// Objects store their type parameters differently (in the object itself
// rather than in the type descriptor).
tag ty_param_storage {
tps_normal;
tps_obj(uint);
}
fn get_derived_tydesc(cx: &@block_ctxt, t: ty::t, escapes: bool,
storage: ty_param_storage,
static_ti: &mutable option::t<@tydesc_info>) -> result {
alt cx.fcx.derived_tydescs.find(t) {
some(info) {
@ -954,10 +964,7 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: ty::t, escapes: bool,
}
bcx_ccx(cx).stats.n_derived_tydescs += 1u;
let bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
let n_params: uint = ty::count_ty_params(bcx_tcx(bcx), t);
let tys = linearize_ty_params(bcx, t);
assert (n_params == std::vec::len::<uint>(tys.params));
assert (n_params == std::vec::len::<ValueRef>(tys.descs));
let root_ti = get_static_tydesc(bcx, t, tys.params);
static_ti = some::<@tydesc_info>(root_ti);
lazily_emit_all_tydesc_glue(cx, static_ti);
@ -966,43 +973,52 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: ty::t, escapes: bool,
bcx = sz.bcx;
let align = align_of(bcx, t);
bcx = align.bcx;
// Store the captured type descriptors in an alloca if the caller isn't
// promising to do so itself.
let n_params = ty::count_ty_params(bcx_tcx(bcx), t);
assert (n_params == std::vec::len::<uint>(tys.params));
assert (n_params == std::vec::len::<ValueRef>(tys.descs));
let llparamtydescs =
alloca(bcx, T_array(T_ptr(bcx_ccx(bcx).tydesc_type), n_params + 1u));
let i = 0;
// If the type descriptor escapes, we need to add in the root as
// the first parameter, because upcall_get_type_desc() expects it.
if escapes {
bld::Store(bcx, root, GEPi(bcx, llparamtydescs, [0, 0]));
i += 1;
}
for td: ValueRef in tys.descs {
bld::Store(bcx, td, GEPi(bcx, llparamtydescs, [0, i]));
i += 1;
}
let llfirstparam =
bld::PointerCast(bcx, llparamtydescs,
T_ptr(T_ptr(bcx_ccx(bcx).tydesc_type)));
let obj_params;
alt storage {
tps_normal. { obj_params = 0u; }
tps_obj(np) { obj_params = np; }
}
let v;
if escapes {
/* for root*/
let tydescs =
alloca(bcx,
T_array(T_ptr(bcx_ccx(bcx).tydesc_type), 1u + n_params));
let i = 0;
let tdp = bld::GEP(bcx, tydescs, [C_int(0), C_int(i)]);
bld::Store(bcx, root, tdp);
i += 1;
for td: ValueRef in tys.descs {
let tdp = bld::GEP(bcx, tydescs, [C_int(0), C_int(i)]);
bld::Store(bcx, td, tdp);
i += 1;
}
let lltydescsptr =
bld::PointerCast(bcx, tydescs,
T_ptr(T_ptr(bcx_ccx(bcx).tydesc_type)));
let td_val =
bld::Call(bcx, bcx_ccx(bcx).upcalls.get_type_desc,
[bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())), sz.val,
align.val, C_int(1u + n_params as int),
lltydescsptr]);
align.val, C_uint(1u + n_params),
llfirstparam, C_uint(obj_params)]);
v = td_val;
} else {
let llparamtydescs =
alloca(bcx,
T_array(T_ptr(bcx_ccx(bcx).tydesc_type), n_params + 1u));
let i = 0;
for td: ValueRef in tys.descs {
let tdp = bld::GEP(bcx, llparamtydescs, [C_int(0), C_int(i)]);
bld::Store(bcx, td, tdp);
i += 1;
}
v =
trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
llparamtydescs, n_params);
v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
llfirstparam, n_params,
obj_params);
}
bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
ret rslt(cx, v);
@ -1011,6 +1027,7 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: ty::t, escapes: bool,
type get_tydesc_result = {kind: tydesc_kind, result: result};
fn get_tydesc(cx: &@block_ctxt, orig_t: ty::t, escapes: bool,
storage: ty_param_storage,
static_ti: &mutable option::t<@tydesc_info>) ->
get_tydesc_result {
@ -1036,7 +1053,7 @@ fn get_tydesc(cx: &@block_ctxt, orig_t: ty::t, escapes: bool,
// Does it contain a type param? If so, generate a derived tydesc.
if ty::type_contains_params(bcx_tcx(cx), t) {
ret {kind: tk_derived,
result: get_derived_tydesc(cx, t, escapes, static_ti)};
result: get_derived_tydesc(cx, t, escapes, storage, static_ti)};
}
// Otherwise, generate a tydesc if necessary, and return it.
@ -1264,7 +1281,8 @@ fn emit_tydescs(ccx: &@crate_ctxt) {
cmp_glue, // cmp_glue
C_shape(ccx, shape), // shape
shape_tables, // shape_tables
C_int(0)]); // n_params
C_int(0), // n_params
C_int(0)]); // n_obj_params
let gvar = ti.tydesc;
llvm::LLVMSetInitializer(gvar, tydesc);
@ -1483,7 +1501,7 @@ fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: &ast::def_id,
let args = [cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env];
for tp: ty::t in tps {
let ti: option::t<@tydesc_info> = none;
let td = get_tydesc(cx, tp, false, ti).result;
let td = get_tydesc(cx, tp, false, tps_normal, ti).result;
args += [td.val];
cx = td.bcx;
}
@ -2143,7 +2161,7 @@ fn call_tydesc_glue_full(cx: &@block_ctxt, v: ValueRef, tydesc: ValueRef,
fn call_tydesc_glue(cx: &@block_ctxt, v: ValueRef, t: ty::t, field: int) ->
result {
let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
let td = get_tydesc(cx, t, false, ti).result;
let td = get_tydesc(cx, t, false, tps_normal, ti).result;
call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
field, ti);
ret rslt(td.bcx, C_nil());
@ -2159,7 +2177,7 @@ fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: ty::t,
let llrawlhsptr = bld::BitCast(cx, lllhs, T_ptr(T_i8()));
let llrawrhsptr = bld::BitCast(cx, llrhs, T_ptr(T_i8()));
let ti = none::<@tydesc_info>;
let r = get_tydesc(cx, t, false, ti).result;
let r = get_tydesc(cx, t, false, tps_normal, ti).result;
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
let lltydesc = r.val;
let lltydescs =
@ -2194,7 +2212,8 @@ fn call_copy_glue(cx: &@block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t,
let srcptr = bld::BitCast(cx, src, T_ptr(T_i8()));
let dstptr = bld::BitCast(cx, dst, T_ptr(T_i8()));
let ti = none;
let {bcx, val: lltydesc} = get_tydesc(cx, t, false, ti).result;
let {bcx, val: lltydesc} =
get_tydesc(cx, t, false, tps_normal, ti).result;
lazily_emit_tydesc_glue(cx, abi::tydesc_field_copy_glue, ti);
let lltydescs = bld::GEP
(bcx, lltydesc, [C_int(0), C_int(abi::tydesc_field_first_param)]);
@ -2594,10 +2613,10 @@ fn trans_evec_append(cx: &@block_ctxt, t: ty::t, lhs: ValueRef,
}
let bcx = cx;
let ti = none::<@tydesc_info>;
let llvec_tydesc = get_tydesc(bcx, t, false, ti).result;
let llvec_tydesc = get_tydesc(bcx, t, false, tps_normal, ti).result;
bcx = llvec_tydesc.bcx;
ti = none::<@tydesc_info>;
let llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti).result;
let llelt_tydesc = get_tydesc(bcx, elt_ty, false, tps_normal, ti).result;
lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
@ -2956,7 +2975,8 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef],
if copying {
let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]);
let ti = none;
let bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti).result;
let bindings_tydesc =
get_tydesc(bcx, bindings_ty, true, tps_normal, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = bindings_tydesc.bcx;
@ -3273,7 +3293,7 @@ fn lval_generic_fn(cx: &@block_ctxt, tpt: &ty::ty_param_kinds_and_ty,
// TODO: Doesn't always escape.
let ti = none::<@tydesc_info>;
let td = get_tydesc(bcx, t, true, ti).result;
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
tis += [ti];
bcx = td.bcx;
tydescs += [td.val];
@ -4526,7 +4546,7 @@ fn trans_log(lvl: int, cx: &@block_ctxt, e: &@ast::expr) -> result {
let log_bcx = sub.bcx;
let ti = none::<@tydesc_info>;
let r = get_tydesc(log_bcx, e_ty, false, ti).result;
let r = get_tydesc(log_bcx, e_ty, false, tps_normal, ti).result;
log_bcx = r.bcx;
// Call the polymorphic log function.

View file

@ -640,7 +640,7 @@ fn T_tydesc(taskptr_type: TypeRef) -> TypeRef {
let elems =
[tydescpp, T_int(), T_int(), glue_fn_ty, glue_fn_ty, glue_fn_ty,
copy_glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, cmp_glue_fn_ty,
T_ptr(T_i8()), T_ptr(T_i8()), T_int()];
T_ptr(T_i8()), T_ptr(T_i8()), T_int(), T_int()];
set_struct_body(tydesc, elems);
ret tydesc;
}

View file

@ -8,7 +8,7 @@ import trans::{call_memmove, trans_shared_malloc, llsize_of,
alloca, array_alloca, size_of, llderivedtydescs_block_ctxt,
lazily_emit_tydesc_glue, get_tydesc, load_inbounds,
move_val_if_temp, trans_lval, node_id_type,
new_sub_block_ctxt};
new_sub_block_ctxt, tps_normal};
import bld = trans_build;
import trans_common::*;
@ -360,9 +360,9 @@ fn trans_append(cx: &@block_ctxt, t: ty::t, lhs: ValueRef,
// FIXME (issue #511): This is needed to prevent a leak.
let no_tydesc_info = none;
rs = get_tydesc(bcx, t, false, no_tydesc_info).result;
rs = get_tydesc(bcx, t, false, tps_normal, no_tydesc_info).result;
bcx = rs.bcx;
rs = get_tydesc(bcx, unit_ty, false, no_tydesc_info).result;
rs = get_tydesc(bcx, unit_ty, false, tps_normal, no_tydesc_info).result;
bcx = rs.bcx;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
@ -448,7 +448,8 @@ fn trans_append_literal(bcx: &@block_ctxt, v: ValueRef, vec_ty: ty::t,
vals: &[@ast::expr]) -> @block_ctxt {
let elt_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
let ti = none;
let {bcx, val: td} = get_tydesc(bcx, elt_ty, false, ti).result;
let {bcx, val: td} =
get_tydesc(bcx, elt_ty, false, tps_normal, ti).result;
trans::lazily_emit_all_tydesc_glue(bcx, ti);
let opaque_v = bld::PointerCast(bcx, v, T_ptr(T_opaque_ivec()));
for val in vals {

View file

@ -2,6 +2,7 @@
import std::str;
import std::option;
import std::vec;
import option::none;
import option::some;
@ -133,7 +134,14 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_tydesc]);
bcx = body_tydesc.bcx;
let ti = none::<@tydesc_info>;
let body_td = get_tydesc(bcx, body_ty, true, ti).result;
let r = GEP_tup_like(bcx, body_ty, body,
[0, abi::obj_body_elt_typarams]);
bcx = r.bcx;
let body_typarams = r.val;
let storage = tps_obj(vec::len(ty_params));
let body_td = get_tydesc(bcx, body_ty, true, storage, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = body_td.bcx;
@ -147,16 +155,13 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
// Likewise for the object's fields.)
// Copy typarams into captured typarams.
let body_typarams =
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_typarams]);
bcx = body_typarams.bcx;
// TODO: can we just get typarams_ty out of body_ty instead?
let typarams_ty: ty::t = ty::mk_tup(ccx.tcx, tps);
let i: int = 0;
for tp: ast::ty_param in ty_params {
let typaram = bcx.fcx.lltydescs[i];
let capture =
GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
GEP_tup_like(bcx, typarams_ty, body_typarams, [0, i]);
bcx = capture.bcx;
bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty);
i += 1;
@ -323,7 +328,7 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_tydesc]);
bcx = body_tydesc.bcx;
let ti = none::<@tydesc_info>;
let body_td = get_tydesc(bcx, body_ty, true, ti).result;
let body_td = get_tydesc(bcx, body_ty, true, tps_normal, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = body_td.bcx;

View file

@ -5,7 +5,8 @@ type_desc *
rust_crate_cache::get_type_desc(size_t size,
size_t align,
size_t n_descs,
type_desc const **descs)
type_desc const **descs,
uintptr_t n_obj_params)
{
I(sched, n_descs > 1);
type_desc *td = NULL;
@ -35,6 +36,7 @@ rust_crate_cache::get_type_desc(size_t size,
// FIXME (issue #136): Below is a miscalculation.
td->is_stateful |= descs[i]->is_stateful;
}
td->n_obj_params = n_obj_params;
HASH_ADD(hh, this->type_descs, descs, keysz, td);
return td;
}

View file

@ -284,7 +284,8 @@ struct type_desc {
cmp_glue_fn *cmp_glue;
const uint8_t *shape;
const rust_shape_tables *shape_tables;
uint32_t n_params;
uintptr_t n_params;
uintptr_t n_obj_params;
// Residual fields past here are known only to runtime.
UT_hash_handle hh;

View file

@ -3,14 +3,13 @@
struct rust_scheduler;
class
rust_crate_cache
{
class rust_crate_cache {
public:
type_desc *get_type_desc(size_t size,
size_t align,
size_t n_descs,
type_desc const **descs);
type_desc const **descs,
uintptr_t n_obj_params);
private:

View file

@ -339,7 +339,8 @@ upcall_get_type_desc(rust_task *task,
size_t size,
size_t align,
size_t n_descs,
type_desc const **descs) {
type_desc const **descs,
uintptr_t n_obj_params) {
check_stack(task);
LOG_UPCALL_ENTRY(task);
@ -347,7 +348,8 @@ upcall_get_type_desc(rust_task *task,
", align=%" PRIdPTR ", %" PRIdPTR " descs", size, align,
n_descs);
rust_crate_cache *cache = task->get_crate_cache();
type_desc *td = cache->get_type_desc(size, align, n_descs, descs);
type_desc *td = cache->get_type_desc(size, align, n_descs, descs,
n_obj_params);
LOG(task, cache, "returning tydesc 0x%" PRIxPTR, td);
return td;
}