diff options
| author | Michael Sullivan <sully@msully.net> | 2011-06-20 19:40:01 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2011-06-22 07:03:16 -0700 |
| commit | 6b40cedcb1c19dedd9803f27c8d3e6b1f949c0ea (patch) | |
| tree | 3a22d2c8e155b51d57641d3f269049b060752d74 /src/comp | |
| parent | c07443e6ebad98b7a5f4599ef671e468a454d9e2 (diff) | |
| download | rust-6b40cedcb1c19dedd9803f27c8d3e6b1f949c0ea.tar.gz rust-6b40cedcb1c19dedd9803f27c8d3e6b1f949c0ea.zip | |
Pull building the environment for for_each into a seperate function.
Diffstat (limited to 'src/comp')
| -rw-r--r-- | src/comp/middle/trans.rs | 108 |
1 files changed, 61 insertions, 47 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a08027db057..c9e8b0bbc30 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4196,45 +4196,17 @@ fn collect_upvars(&@block_ctxt cx, &ast::block bloc, ret result; } -fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, - &ast::block body) -> result { - /* - * The translation is a little .. complex here. Code like: - * - * let ty1 p = ...; - * - * let ty1 q = ...; - * - * foreach (ty v in foo(a,b)) { body(p,q,v) } - * - * - * Turns into a something like so (C/Rust mishmash): - * - * type env = { *ty1 p, *ty2 q, ... }; - * - * let env e = { &p, &q, ... }; - * - * fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) } - * - * foo([foreach123_body, env*], a, b); - * - */ - - // Step 1: walk body and figure out which references it makes - // escape. This could be determined upstream, and probably ought - // to be so, eventualy. - - auto lcx = cx.fcx.lcx; - // FIXME: possibly support alias-mode here? - - auto decl_ty = node_id_type(lcx.ccx, local.node.id); - auto decl_id = local.node.id; - auto upvars = collect_upvars(cx, body, decl_id); +// Given a block context and a list of upvars, construct a closure that +// contains pointers to all of the upvars and all of the tydescs in +// scope. Return the ValueRef and TypeRef corresponding to the closure. +fn build_environment(&@block_ctxt cx, &vec[ast::node_id] upvars) -> + tup(ValueRef, TypeRef) +{ auto upvar_count = vec::len(upvars); auto llbindingsptr; + if (upvar_count > 0u) { // Gather up the upvars. - let vec[ValueRef] llbindings = []; let vec[TypeRef] llbindingtys = []; for (ast::node_id nid in upvars) { @@ -4253,8 +4225,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, llbindings += [llbinding]; llbindingtys += [val_ty(llbinding)]; } - // Create an array of bindings and copy in aliases to the upvars. + // Create an array of bindings and copy in aliases to the upvars. llbindingsptr = alloca(cx, T_struct(llbindingtys)); auto i = 0u; while (i < upvar_count) { @@ -4265,23 +4237,22 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, } } else { // Null bindings. - llbindingsptr = C_null(T_ptr(T_i8())); } - // Create an environment and populate it with the bindings. + // Create an environment and populate it with the bindings. auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs); auto llenvptrty = - T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()), val_ty(llbindingsptr), - tydesc_count); + T_closure_ptr(cx.fcx.lcx.ccx.tn, T_ptr(T_nil()), + val_ty(llbindingsptr), tydesc_count); auto llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty)); auto llbindingsptrptr = cx.build.GEP(llenvptr, [C_int(0), C_int(abi::box_rc_field_body), C_int(2)]); cx.build.Store(llbindingsptr, llbindingsptrptr); + // Copy in our type descriptors, in case the iterator body needs to refer // to them. - auto lltydescsptr = cx.build.GEP(llenvptr, [C_int(0), C_int(abi::box_rc_field_body), @@ -4293,16 +4264,58 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr); i += 1u; } - // Step 2: Declare foreach body function. + ret tup(llenvptr, llenvptrty); +} + +fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, + &ast::block body) -> result { + /* + * The translation is a little .. complex here. Code like: + * + * let ty1 p = ...; + * + * let ty1 q = ...; + * + * foreach (ty v in foo(a,b)) { body(p,q,v) } + * + * + * Turns into a something like so (C/Rust mishmash): + * + * type env = { *ty1 p, *ty2 q, ... }; + * + * let env e = { &p, &q, ... }; + * + * fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) } + * + * foo([foreach123_body, env*], a, b); + * + */ + + // Step 1: walk body and figure out which references it makes + // escape. This could be determined upstream, and probably ought + // to be so, eventualy. + auto lcx = cx.fcx.lcx; + + // FIXME: possibly support alias-mode here? + auto decl_ty = node_id_type(lcx.ccx, local.node.id); + auto decl_id = local.node.id; + auto upvars = collect_upvars(cx, body, decl_id); + auto upvar_count = vec::len(upvars); + + auto environment_data = build_environment(cx, upvars); + auto llenvptr = environment_data._0; + auto llenvptrty = environment_data._1; + + // Step 2: Declare foreach body function. let str s = mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach"); + // The 'env' arg entering the body function is a fake env member (as in // the env-part of the normal rust calling convention) that actually // points to a stack allocated env in this frame. We bundle that env // pointer along with the foreach-body-fn pointer into a 'normal' fn pair // and pass it in as a first class fn-arg to the iterator. - auto iter_body_llty = type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, none[TypeRef], [rec(mode=ty::mo_alias(false), ty=decl_ty)], @@ -4311,8 +4324,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty); auto fcx = new_fn_ctxt(lcx, cx.sp, lliterbody); auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs); - // Populate the upvars from the environment. + // Populate the upvars from the environment. auto llremoteenvptr = copy_args_bcx.build.PointerCast(fcx.llenv, llenvptrty); auto llremotebindingsptrptr = @@ -4321,7 +4334,7 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, C_int(abi::closure_elt_bindings)]); auto llremotebindingsptr = copy_args_bcx.build.Load(llremotebindingsptrptr); - i = 0u; + auto i = 0u; while (i < upvar_count) { auto upvar_id = upvars.(i); auto llupvarptrptr = @@ -4331,12 +4344,13 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, fcx.llupvars.insert(upvar_id, llupvarptr); i += 1u; } - // Populate the type parameters from the environment. + // Populate the type parameters from the environment. auto llremotetydescsptr = copy_args_bcx.build.GEP(llremoteenvptr, [C_int(0), C_int(abi::box_rc_field_body), C_int(abi::closure_elt_ty_params)]); + auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs); i = 0u; while (i < tydesc_count) { auto llremotetydescptr = @@ -4346,8 +4360,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, fcx.lltydescs += [llremotetydesc]; i += 1u; } - // Add an upvar for the loop variable alias. + // Add an upvar for the loop variable alias. fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u)); auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; |
