Skip to content

Commit f371482

Browse files
committed
Consolidate environment building/loading between closure types.
1 parent 4cf4e17 commit f371482

File tree

3 files changed

+102
-153
lines changed

3 files changed

+102
-153
lines changed

src/comp/middle/trans.rs

Lines changed: 83 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,7 @@ fn type_of_fn_full(cx: &@crate_ctxt, sp: &span, proto: ast::proto,
145145
// *input* type of the function we're given as our iter-block
146146
// argument.
147147
atys +=
148-
~[T_fn_pair(*cx,
149-
type_of_fn_full(cx, sp, ast::proto_fn, false,
150-
~[{mode: ty::mo_alias(false),
151-
ty: output}], ty::mk_nil(cx.tcx),
152-
0u))];
148+
~[type_of_inner(cx, sp, ty::mk_iter_body_fn(cx.tcx, output))];
153149
}
154150

155151
// ... then explicit args.
@@ -863,15 +859,13 @@ fn trans_malloc_boxed_raw(cx: &@block_ctxt, t: ty::t) -> result {
863859
// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box,
864860
// initializes the reference count to 1, and pulls out the body and rc
865861
fn trans_malloc_boxed(cx: &@block_ctxt, t: ty::t) ->
866-
{bcx: @block_ctxt, box: ValueRef, rc: ValueRef, body: ValueRef} {
862+
{bcx: @block_ctxt, box: ValueRef, body: ValueRef} {
867863
let res = trans_malloc_boxed_raw(cx, t);
868864
let box = res.val;
869-
let rc = res.bcx.build.GEP(box,
870-
~[C_int(0), C_int(abi::box_rc_field_refcnt)]);
865+
let rc = GEPi(res.bcx, box, ~[0, abi::box_rc_field_refcnt]);
871866
res.bcx.build.Store(C_int(1), rc);
872-
let body = res.bcx.build.GEP(box,
873-
~[C_int(0), C_int(abi::box_rc_field_body)]);
874-
ret {bcx: res.bcx, box: res.val, rc: rc, body: body};
867+
let body = GEPi(res.bcx, box, ~[0, abi::box_rc_field_body]);
868+
ret {bcx: res.bcx, box: res.val, body: body};
875869
}
876870

877871
// Type descriptor and type glue stuff
@@ -3645,11 +3639,13 @@ fn trans_for(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
36453639

36463640
// Iterator translation
36473641

3648-
// build_environment_heap and build_environment are very similar. It
3649-
// would be nice to unify them.
3650-
3651-
fn build_environment_heap(bcx: @block_ctxt, lltydescs: ValueRef[],
3652-
bound_tys: ty::t[], bound_vals: lval_result[])
3642+
// Given a block context and a list of tydescs and values to bind
3643+
// construct a closure out of them. If copying is true, it is a
3644+
// heap allocated closure that copies the upvars into environment.
3645+
// Otherwise, it is stack allocated and copies pointers to the upvars.
3646+
fn build_environment(bcx: @block_ctxt, lltydescs: ValueRef[],
3647+
bound_tys: ty::t[], bound_vals: lval_result[],
3648+
copying: bool)
36533649
-> {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} {
36543650
// Synthesize a closure type.
36553651

@@ -3682,18 +3678,29 @@ fn build_environment_heap(bcx: @block_ctxt, lltydescs: ValueRef[],
36823678
let closure_ty: ty::t = ty::mk_imm_tup(bcx_tcx(bcx), closure_tys);
36833679

36843680
// Allocate a box that can hold something closure-sized.
3685-
let r = trans_malloc_boxed(bcx, closure_ty);
3681+
let r = if copying {
3682+
trans_malloc_boxed(bcx, closure_ty)
3683+
} else {
3684+
// We need to dummy up a box on the stack
3685+
let ty = ty::mk_imm_tup(bcx_tcx(bcx),
3686+
~[ty::mk_int(bcx_tcx(bcx)), closure_ty]);
3687+
let r = alloc_ty(bcx, ty);
3688+
let body = GEPi(bcx, r.val, ~[0, abi::box_rc_field_body]);
3689+
{bcx: r.bcx, box: r.val, body: body}
3690+
};
36863691
bcx = r.bcx;
36873692
let closure = r.body;
36883693

36893694
// Store bindings tydesc.
3690-
let bound_tydesc = GEPi(bcx, closure, ~[0, abi::closure_elt_tydesc]);
3691-
let ti = none;
3692-
let bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
3693-
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
3694-
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
3695-
bcx = bindings_tydesc.bcx;
3696-
bcx.build.Store(bindings_tydesc.val, bound_tydesc);
3695+
if copying {
3696+
let bound_tydesc = GEPi(bcx, closure, ~[0, abi::closure_elt_tydesc]);
3697+
let ti = none;
3698+
let bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
3699+
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
3700+
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
3701+
bcx = bindings_tydesc.bcx;
3702+
bcx.build.Store(bindings_tydesc.val, bound_tydesc);
3703+
}
36973704

36983705
// Copy expr values into boxed bindings.
36993706
let i = 0u;
@@ -3704,8 +3711,13 @@ fn build_environment_heap(bcx: @block_ctxt, lltydescs: ValueRef[],
37043711
for lv: lval_result in bound_vals {
37053712
let bound = GEP_tup_like(bcx, bindings_ty, bindings.val,
37063713
~[0, i as int]);
3707-
bcx = move_val_if_temp(bound.bcx, INIT,
3708-
bound.val, lv, bound_tys.(i)).bcx;
3714+
bcx = bound.bcx;
3715+
if copying {
3716+
bcx = move_val_if_temp(bcx, INIT,
3717+
bound.val, lv, bound_tys.(i)).bcx;
3718+
} else {
3719+
bcx.build.Store(lv.res.val, bound.val);
3720+
}
37093721
i += 1u;
37103722
}
37113723

@@ -3725,78 +3737,27 @@ fn build_environment_heap(bcx: @block_ctxt, lltydescs: ValueRef[],
37253737
ret {ptr: r.box, ptrty: closure_ty, bcx: bcx};
37263738
}
37273739

3728-
fn build_copying_closure(cx: &@block_ctxt, upvars: &@ast::node_id[])
3740+
// Given a context and a list of upvars, build a closure. This just
3741+
// collects the upvars and packages them up for build_environment.
3742+
fn build_closure(cx: &@block_ctxt, upvars: &@ast::node_id[], copying: bool)
37293743
-> {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} {
37303744
let closure_vals: lval_result[] = ~[];
37313745
let closure_tys: ty::t[] = ~[];
3732-
for nid: ast::node_id in *upvars {
3733-
closure_vals += ~[trans_var(cx, cx.sp, nid)];
3734-
closure_tys += ~[ty::node_id_to_monotype(bcx_tcx(cx), nid)];
3735-
}
3736-
3737-
ret build_environment_heap(cx, cx.fcx.lltydescs,
3738-
closure_tys, closure_vals);
3739-
}
3740-
3741-
// Given a block context and a list of upvars, construct a closure that
3742-
// contains pointers to all of the upvars and all of the tydescs in
3743-
// scope. Return the ValueRef and TypeRef corresponding to the closure.
3744-
fn build_environment(cx: &@block_ctxt, upvars: &@ast::node_id[]) ->
3745-
{ptr: ValueRef, ptrty: TypeRef} {
3746-
let has_iterbody = !option::is_none(cx.fcx.lliterbody);
3747-
let llbindingsptr;
3748-
3749-
if std::ivec::len(*upvars) > 0u || has_iterbody {
3750-
// Gather up the upvars.
3751-
let llbindings: ValueRef[] = ~[];
3752-
let llbindingtys: TypeRef[] = ~[];
3753-
if has_iterbody {
3754-
llbindings += ~[option::get(cx.fcx.lliterbody)];
3755-
llbindingtys += ~[val_ty(llbindings.(0))];
3746+
// If we need to, package up the iterator body to call
3747+
if !copying && !option::is_none(cx.fcx.lliterbody) {
3748+
closure_vals += ~[lval_mem(cx, option::get(cx.fcx.lliterbody))];
3749+
closure_tys += ~[option::get(cx.fcx.iterbodyty)];
37563750
}
3751+
// Package up the upvars
37573752
for nid: ast::node_id in *upvars {
3758-
let llbinding = trans_var(cx, cx.sp, nid).res.val;
3759-
llbindings += ~[llbinding];
3760-
llbindingtys += ~[val_ty(llbinding)];
3761-
}
3762-
3763-
// Create an array of bindings and copy in aliases to the upvars.
3764-
llbindingsptr = alloca(cx, T_struct(llbindingtys));
3765-
let upvar_count = std::ivec::len(llbindings);
3766-
let i = 0u;
3767-
while i < upvar_count {
3768-
let llbindingptr = GEPi(cx, llbindingsptr, ~[0, i as int]);
3769-
cx.build.Store(llbindings.(i), llbindingptr);
3770-
i += 1u;
3753+
closure_vals += ~[trans_var(cx, cx.sp, nid)];
3754+
let ty = ty::node_id_to_monotype(bcx_tcx(cx), nid);
3755+
if !copying { ty = ty::mk_mut_ptr(bcx_tcx(cx), ty); }
3756+
closure_tys += ~[ty];
37713757
}
3772-
} else {
3773-
// Null bindings.
3774-
llbindingsptr = C_null(T_ptr(T_i8()));
3775-
}
3776-
3777-
// Create an environment and populate it with the bindings.
3778-
let tydesc_count = std::ivec::len(cx.fcx.lltydescs);
3779-
let llenvptrty =
3780-
T_closure_ptr(*bcx_ccx(cx), val_ty(llbindingsptr), tydesc_count);
3781-
let llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty));
3782-
let llbindingsptrptr =
3783-
GEPi(cx, llenvptr,
3784-
~[0, abi::box_rc_field_body, abi::closure_elt_bindings]);
3785-
cx.build.Store(llbindingsptr, llbindingsptrptr);
3786-
3787-
// Copy in our type descriptors, in case the iterator body needs to refer
3788-
// to them.
3789-
let lltydescsptr =
3790-
GEPi(cx, llenvptr,
3791-
~[0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
3792-
let i = 0u;
3793-
while i < tydesc_count {
3794-
let lltydescptr = GEPi(cx, lltydescsptr, ~[0, i as int]);
3795-
cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
3796-
i += 1u;
3797-
}
37983758

3799-
ret {ptr: llenvptr, ptrty: llenvptrty};
3759+
ret build_environment(cx, cx.fcx.lltydescs,
3760+
closure_tys, closure_vals, copying);
38003761
}
38013762

38023763
// Return a pointer to the stored typarams in a closure.
@@ -3829,8 +3790,12 @@ fn find_environment_tydescs(bcx: &@block_ctxt, envty: &ty::t,
38293790
}
38303791
}
38313792

3832-
fn load_environment_heap(enclosing_cx: &@block_ctxt, fcx: &@fn_ctxt,
3833-
envty: &ty::t, upvars: &@ast::node_id[]) {
3793+
// Given an enclosing block context, a new function context, a closure type,
3794+
// and a list of upvars, generate code to load and populate the environment
3795+
// with the upvars and type descriptors.
3796+
fn load_environment(enclosing_cx: &@block_ctxt, fcx: &@fn_ctxt,
3797+
envty: &ty::t, upvars: &@ast::node_id[],
3798+
copying: bool) {
38343799
let bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
38353800

38363801
let ty = ty::mk_imm_box(bcx_tcx(bcx), envty);
@@ -3852,54 +3817,25 @@ fn load_environment_heap(enclosing_cx: &@block_ctxt, fcx: &@fn_ctxt,
38523817
// Populate the upvars from the environment.
38533818
let path = ~[0, abi::box_rc_field_body, abi::closure_elt_bindings];
38543819
i = 0u;
3855-
for upvar_id: ast::node_id in *upvars {
3856-
let llupvarptr =
3857-
GEP_tup_like(bcx, ty, llclosure, path + ~[i as int]);
3858-
bcx = llupvarptr.bcx;
3859-
let def_id = ast::def_id_of_def(bcx_tcx(bcx).def_map.get(upvar_id));
3860-
fcx.llupvars.insert(def_id.node, llupvarptr.val);
3820+
// If this is an aliasing closure/for-each body, we need to load
3821+
// the iterbody.
3822+
if !copying && !option::is_none(enclosing_cx.fcx.lliterbody) {
3823+
let iterbodyptr = GEP_tup_like(bcx, ty, llclosure, path + ~[0]);
3824+
fcx.lliterbody = some(bcx.build.Load(iterbodyptr.val));
3825+
bcx = iterbodyptr.bcx;
38613826
i += 1u;
38623827
}
3863-
}
3864-
3865-
3866-
// Given an enclosing block context, a new function context, a closure type,
3867-
// and a list of upvars, generate code to load and populate the environment
3868-
// with the upvars and type descriptors.
3869-
fn load_environment(enclosing_cx: &@block_ctxt, fcx: &@fn_ctxt,
3870-
llenvptrty: TypeRef, upvars: &@ast::node_id[]) {
3871-
let bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
3872-
3873-
// Populate the upvars from the environment.
3874-
let llenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
3875-
llenvptr = GEPi(bcx, llenvptr, ~[0, abi::box_rc_field_body]);
3876-
let llbindingsptrptr =
3877-
GEPi(bcx, llenvptr, ~[0, abi::closure_elt_bindings]);
3878-
let llbindingsptr = bcx.build.Load(llbindingsptrptr);
3879-
3880-
let i = 0u;
3881-
if !option::is_none(enclosing_cx.fcx.lliterbody) {
3882-
i += 1u;
3883-
let lliterbodyptr = GEPi(bcx, llbindingsptr, ~[0, 0]);
3884-
fcx.lliterbody = some(bcx.build.Load(lliterbodyptr));
3885-
}
3828+
// Load the acutal upvars.
38863829
for upvar_id: ast::node_id in *upvars {
3887-
let llupvarptrptr = GEPi(bcx, llbindingsptr, ~[0, i as int]);
3888-
let llupvarptr = bcx.build.Load(llupvarptrptr);
3830+
let upvarptr =
3831+
GEP_tup_like(bcx, ty, llclosure, path + ~[i as int]);
3832+
bcx = upvarptr.bcx;
3833+
let llupvarptr = upvarptr.val;
3834+
if !copying { llupvarptr = bcx.build.Load(llupvarptr); }
38893835
let def_id = ast::def_id_of_def(bcx_tcx(bcx).def_map.get(upvar_id));
38903836
fcx.llupvars.insert(def_id.node, llupvarptr);
38913837
i += 1u;
38923838
}
3893-
3894-
// Populate the type parameters from the environment.
3895-
let lltydescsptr = GEPi(bcx, llenvptr, ~[0, abi::closure_elt_ty_params]);
3896-
let tydesc_count = std::ivec::len(enclosing_cx.fcx.lltydescs);
3897-
i = 0u;
3898-
while i < tydesc_count {
3899-
let lltydescptr = GEPi(bcx, lltydescsptr, ~[0, i as int]);
3900-
fcx.lltydescs += ~[bcx.build.Load(lltydescptr)];
3901-
i += 1u;
3902-
}
39033839
}
39043840

39053841
fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
@@ -3934,7 +3870,7 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
39343870
let decl_ty = node_id_type(lcx.ccx, local.node.id);
39353871
let upvars = get_freevars(lcx.ccx.tcx, body.node.id);
39363872

3937-
let llenv = build_environment(cx, upvars);
3873+
let llenv = build_closure(cx, upvars, false);
39383874

39393875
// Step 2: Declare foreach body function.
39403876
let s: str =
@@ -3946,16 +3882,16 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
39463882
// pointer along with the foreach-body-fn pointer into a 'normal' fn pair
39473883
// and pass it in as a first class fn-arg to the iterator.
39483884
let iter_body_llty =
3949-
type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, false,
3950-
~[{mode: ty::mo_alias(false), ty: decl_ty}],
3951-
ty::mk_nil(lcx.ccx.tcx), 0u);
3885+
type_of_fn_from_ty(lcx.ccx, cx.sp,
3886+
ty::mk_iter_body_fn(lcx.ccx.tcx, decl_ty), 0u);
39523887
let lliterbody: ValueRef =
39533888
decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty);
39543889
let fcx = new_fn_ctxt_w_id(lcx, cx.sp, lliterbody, body.node.id);
3890+
fcx.iterbodyty = cx.fcx.iterbodyty;
39553891

39563892
// Generate code to load the environment out of the
39573893
// environment pointer.
3958-
load_environment(cx, fcx, llenv.ptrty, upvars);
3894+
load_environment(cx, fcx, llenv.ptrty, upvars, false);
39593895

39603896
let bcx = new_top_block_ctxt(fcx);
39613897
// Add bindings for the loop variable alias.
@@ -4684,8 +4620,8 @@ fn trans_bind_1(cx: &@block_ctxt, f: &@ast::expr, f_res: &lval_result,
46844620
}
46854621

46864622
// Actually construct the closure
4687-
let closure = build_environment_heap(bcx, lltydescs,
4688-
bound_tys, bound_vals);
4623+
let closure = build_environment(bcx, lltydescs,
4624+
bound_tys, bound_vals, true);
46894625
bcx = closure.bcx;
46904626

46914627
// Make thunk
@@ -6236,6 +6172,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: &span, llfndecl: ValueRef,
62366172
mutable lldynamicallocas: llbbs.da,
62376173
mutable llself: none[val_self_pair],
62386174
mutable lliterbody: none[ValueRef],
6175+
mutable iterbodyty: none[ty::t],
62396176
llargs: llargs,
62406177
llobjfields: llobjfields,
62416178
lllocals: lllocals,
@@ -6271,7 +6208,6 @@ fn create_llargs_for_fn_args(cx: &@fn_ctxt, proto: ast::proto,
62716208
// Skip the implicit arguments 0, 1, and 2. TODO: Pull out 3u and define
62726209
// it as a constant, since we're using it in several places in trans this
62736210
// way.
6274-
62756211
let arg_n = 3u;
62766212
alt ty_self {
62776213
some(tt) { cx.llself = some[val_self_pair]({v: cx.llenv, t: tt}); }
@@ -6286,18 +6222,18 @@ fn create_llargs_for_fn_args(cx: &@fn_ctxt, proto: ast::proto,
62866222
}
62876223
}
62886224
}
6225+
62896226
// If the function is actually an iter, populate the lliterbody field of
62906227
// the function context with the ValueRef that we get from
62916228
// llvm::LLVMGetParam for the iter's body.
6292-
62936229
if proto == ast::proto_iter {
6230+
cx.iterbodyty = some(ty::mk_iter_body_fn(fcx_tcx(cx), ret_ty));
62946231
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
62956232
assert (llarg as int != 0);
62966233
cx.lliterbody = some[ValueRef](llarg);
62976234
arg_n += 1u;
62986235
}
62996236

6300-
63016237
// Populate the llargs field of the function context with the ValueRefs
63026238
// that we get from llvm::LLVMGetParam for each argument.
63036239
for arg: ast::arg in args {
@@ -6468,15 +6404,9 @@ fn trans_closure(bcx_maybe: &option::t[@block_ctxt],
64686404
let bcx = option::get(bcx_maybe);
64696405
let upvars = get_freevars(cx.ccx.tcx, id);
64706406

6471-
let env = if (f.proto == ast::proto_block) {
6472-
let llenv = build_environment(bcx, upvars);
6473-
load_environment(bcx, fcx, llenv.ptrty, upvars);
6474-
{ptr: llenv.ptr, bcx: bcx}
6475-
} else {
6476-
let llenv = build_copying_closure(bcx, upvars);
6477-
load_environment_heap(bcx, fcx, llenv.ptrty, upvars);
6478-
{ptr: llenv.ptr, bcx: llenv.bcx}
6479-
};
6407+
let copying = f.proto == ast::proto_closure;
6408+
let env = build_closure(bcx, upvars, copying);
6409+
load_environment(bcx, fcx, env.ptrty, upvars, copying);
64806410

64816411
let closure = create_real_fn_pair(env.bcx, option::get(llfnty),
64826412
llfndecl, env.ptr);

0 commit comments

Comments
 (0)