From 880fd788eb04717d7a75bd5bbf0b8f0a692bda53 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 24 Aug 2011 18:36:51 -0700 Subject: [PATCH] rustc: Add an extra flag to object tydescs so that shapes know how to find the captured subtydescs --- src/comp/back/abi.rs | 3 +- src/comp/back/upcall.rs | 2 +- src/comp/middle/gc.rs | 4 +- src/comp/middle/trans.rs | 118 ++++++++++++++++++------------- src/comp/middle/trans_common.rs | 2 +- src/comp/middle/trans_ivec.rs | 9 +-- src/comp/middle/trans_objects.rs | 17 +++-- src/rt/rust_crate_cache.cpp | 4 +- src/rt/rust_internal.h | 3 +- src/rt/rust_scheduler.h | 7 +- src/rt/rust_upcall.cpp | 6 +- 11 files changed, 103 insertions(+), 72 deletions(-) diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs index 2e2bddba592..64f24eb919c 100644 --- a/src/comp/back/abi.rs +++ b/src/comp/back/abi.rs @@ -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; diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 3ff3371c3b0..54648ada6d3 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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: diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index 1fdb17c1887..7ec131053fe 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -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; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 7d41a1e6bd7..e4a35a8d6b6 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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::(tys.params)); - assert (n_params == std::vec::len::(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::(tys.params)); + assert (n_params == std::vec::len::(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. diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index b457ff22b30..c0da0dfb6f8 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -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; } diff --git a/src/comp/middle/trans_ivec.rs b/src/comp/middle/trans_ivec.rs index b0c18dbc522..dd0d02bc11b 100644 --- a/src/comp/middle/trans_ivec.rs +++ b/src/comp/middle/trans_ivec.rs @@ -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 { diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index 5b29b111b6d..17a600e971d 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -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; diff --git a/src/rt/rust_crate_cache.cpp b/src/rt/rust_crate_cache.cpp index 953430beb68..ba5a104b024 100644 --- a/src/rt/rust_crate_cache.cpp +++ b/src/rt/rust_crate_cache.cpp @@ -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; } diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index dd9f1d0cbc8..71e1377e396 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -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; diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h index 6969034f725..ce1796d0658 100644 --- a/src/rt/rust_scheduler.h +++ b/src/rt/rust_scheduler.h @@ -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: diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 174855cac23..9857f06231e 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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; }