From 6a8cb704d9c2543cb30df2e26b992c17e3bc488d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 11 Dec 2011 20:42:37 -0800 Subject: [PATCH] get basic code generation working, clone type descs for lambda[send] --- src/comp/back/upcall.rs | 40 ++++++++++++++-------- src/comp/middle/trans.rs | 71 +++++++++++++++++++++++++++++----------- src/rt/rust_internal.h | 2 ++ src/rt/rust_upcall.cpp | 33 +++++++++++++++++++ 4 files changed, 113 insertions(+), 33 deletions(-) diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 71f33ccb372..1530e5c1453 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -17,6 +17,7 @@ type upcalls = shared_malloc: ValueRef, shared_free: ValueRef, mark: ValueRef, + clone_type_desc: ValueRef, get_type_desc: ValueRef, vec_grow: ValueRef, vec_push: ValueRef, @@ -54,12 +55,18 @@ fn declare_upcalls(targ_cfg: @session::config, malloc: d("malloc", [size_t, T_ptr(tydesc_type)], T_ptr(T_i8())), - free: dv("free", [T_ptr(T_i8()), int_t]), + free: + dv("free", [T_ptr(T_i8()), int_t]), shared_malloc: d("shared_malloc", [size_t, T_ptr(tydesc_type)], T_ptr(T_i8())), - shared_free: dv("shared_free", [T_ptr(T_i8())]), - mark: d("mark", [T_ptr(T_i8())], int_t), + shared_free: + dv("shared_free", [T_ptr(T_i8())]), + mark: + d("mark", [T_ptr(T_i8())], int_t), + clone_type_desc: + d("clone_type_desc", [T_ptr(tydesc_type)], + T_ptr(tydesc_type)), get_type_desc: d("get_type_desc", [T_ptr(T_nil()), size_t, @@ -67,8 +74,7 @@ fn declare_upcalls(targ_cfg: @session::config, T_ptr(T_ptr(tydesc_type)), int_t], T_ptr(tydesc_type)), vec_grow: - dv("vec_grow", [T_ptr(T_ptr(opaque_vec_t)), - int_t]), + dv("vec_grow", [T_ptr(T_ptr(opaque_vec_t)), int_t]), vec_push: dv("vec_push", [T_ptr(T_ptr(opaque_vec_t)), T_ptr(tydesc_type), @@ -80,18 +86,24 @@ fn declare_upcalls(targ_cfg: @session::config, T_i8()]), log_type: dv("log_type", [T_ptr(tydesc_type), T_ptr(T_i8()), T_i32()]), - dynastack_mark: d("dynastack_mark", [], T_ptr(T_i8())), + dynastack_mark: + d("dynastack_mark", [], T_ptr(T_i8())), dynastack_alloc: d("dynastack_alloc_2", [size_t, T_ptr(tydesc_type)], T_ptr(T_i8())), - dynastack_free: dv("dynastack_free", [T_ptr(T_i8())]), - alloc_c_stack: d("alloc_c_stack", [size_t], T_ptr(T_i8())), - call_shim_on_c_stack: d("call_shim_on_c_stack", - // arguments: void *args, void *fn_ptr - [T_ptr(T_i8()), T_ptr(T_i8())], - int_t), - rust_personality: d("rust_personality", [], T_i32()), - reset_stack_limit: dv("reset_stack_limit", []) + dynastack_free: + dv("dynastack_free", [T_ptr(T_i8())]), + alloc_c_stack: + d("alloc_c_stack", [size_t], T_ptr(T_i8())), + call_shim_on_c_stack: + d("call_shim_on_c_stack", + // arguments: void *args, void *fn_ptr + [T_ptr(T_i8()), T_ptr(T_i8())], + int_t), + rust_personality: + d("rust_personality", [], T_i32()), + reset_stack_limit: + dv("reset_stack_limit", []) }; } // diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index b8e73b118d0..95aa6cf3849 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -2188,19 +2188,20 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span, let s = mangle_internal_name_by_path(ccx, sub_cx.path); let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty); - let copying = alt f.proto { - ast::proto_shared(_) | ast::proto_send. { true } - ast::proto_bare. | ast::proto_block. { false } + let mode = alt f.proto { + ast::proto_shared(_) { for_closure } + ast::proto_send. { for_send } + ast::proto_bare. | ast::proto_block. { for_block } }; let env; alt f.proto { ast::proto_block. | ast::proto_shared(_) | ast::proto_send. { let upvars = get_freevars(ccx.tcx, id); - let env_r = build_closure(bcx, upvars, copying); + let env_r = build_closure(bcx, upvars, mode); env = env_r.ptr; bcx = env_r.bcx; trans_closure(sub_cx, sp, f, llfn, none, [], id, {|fcx| - load_environment(bcx, fcx, env_r.ptrty, upvars, copying); + load_environment(bcx, fcx, env_r.ptrty, upvars, mode); }); } ast::proto_bare. { @@ -2560,7 +2561,7 @@ tag environment_value { // Otherwise, it is stack allocated and copies pointers to the upvars. fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], bound_values: [environment_value], - copying: bool) -> + mode: closure_constr_mode) -> {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} { let ccx = bcx_ccx(bcx); let tcx = bcx_tcx(bcx); @@ -2602,13 +2603,15 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], let temp_cleanups = [], bcx = bcx; // Allocate a box that can hold something closure-sized. - let (closure, box) = if copying { + let (closure, box) = alt mode { + for_closure. | for_send. { let r = trans_malloc_boxed(bcx, closure_ty); add_clean_free(bcx, r.box, false); temp_cleanups += [r.box]; bcx = r.bcx; (r.body, r.box) - } else { + } + for_block. { // We need to dummy up a box on the stack let ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]); let r = alloc_ty(bcx, ty); @@ -2618,10 +2621,12 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], C_int(ccx, 2), GEPi(bcx, r.val, [0, abi::box_rc_field_refcnt])); (GEPi(bcx, r.val, [0, abi::box_rc_field_body]), r.val) + } }; // Store bindings tydesc. - if copying { + alt mode { + for_closure. | for_send. { let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]); let ti = none; let bindings_tydesc = @@ -2630,6 +2635,8 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti); bcx = bindings_tydesc.bcx; Store(bcx, bindings_tydesc.val, bound_tydesc); + } + for_block. {} } // Copy expr values into boxed bindings. @@ -2651,12 +2658,15 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], temp_cleanups += [bound.val]; } env_direct(val, ty, is_mem) { - if copying { + alt mode { + for_closure. | for_send. { let val1 = is_mem ? load_if_immediate(bcx, val, ty) : val; bcx = copy_val(bcx, INIT, bound.val, val1, ty); - } else { + } + for_block. { let addr = is_mem ? val : do_spill_noroot(bcx, val); Store(bcx, addr, bound.val); + } } } } @@ -2675,17 +2685,33 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef], i = 0u; for td: ValueRef in lltydescs { let ty_param_slot = GEPi(bcx, ty_params_slot.val, [0, i as int]); - Store(bcx, td, ty_param_slot); + alt mode { + for_closure. | for_block. { + Store(bcx, td, ty_param_slot); + } + for_send. { + let cloned_td = Call(bcx, ccx.upcalls.clone_type_desc, [td]); + Store(bcx, cloned_td, ty_param_slot); + } + } i += 1u; } ret {ptr: box, ptrty: closure_ty, bcx: bcx}; } +tag closure_constr_mode { + for_block; + for_closure; + for_send; +} + // Given a context and a list of upvars, build a closure. This just // collects the upvars and packages them up for build_environment. -fn build_closure(cx: @block_ctxt, upvars: @[ast::def], copying: bool) -> - {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} { +fn build_closure(cx: @block_ctxt, + upvars: @[ast::def], + mode: closure_constr_mode) + -> {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} { // If we need to, package up the iterator body to call let env_vals = []; // Package up the upvars @@ -2693,10 +2719,13 @@ fn build_closure(cx: @block_ctxt, upvars: @[ast::def], copying: bool) -> let lv = trans_local_var(cx, def); let nid = ast_util::def_id_of_def(def).node; let ty = ty::node_id_to_monotype(bcx_tcx(cx), nid); - if !copying { ty = ty::mk_mut_ptr(bcx_tcx(cx), ty); } + alt mode { + for_block. { ty = ty::mk_mut_ptr(bcx_tcx(cx), ty); } + for_send. | for_closure. {} + } env_vals += [env_direct(lv.val, ty, lv.kind == owned)]; } - ret build_environment(cx, copy cx.fcx.lltydescs, env_vals, copying); + ret build_environment(cx, copy cx.fcx.lltydescs, env_vals, mode); } // Return a pointer to the stored typarams in a closure. @@ -2734,7 +2763,7 @@ fn find_environment_tydescs(bcx: @block_ctxt, envty: ty::t, closure: ValueRef) // and a list of upvars, generate code to load and populate the environment // with the upvars and type descriptors. fn load_environment(enclosing_cx: @block_ctxt, fcx: @fn_ctxt, envty: ty::t, - upvars: @[ast::def], copying: bool) { + upvars: @[ast::def], mode: closure_constr_mode) { let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv); let ty = ty::mk_imm_box(bcx_tcx(bcx), envty); @@ -2769,7 +2798,10 @@ fn load_environment(enclosing_cx: @block_ctxt, fcx: @fn_ctxt, envty: ty::t, let upvarptr = GEP_tup_like(bcx, ty, llclosure, path + [i as int]); bcx = upvarptr.bcx; let llupvarptr = upvarptr.val; - if !copying { llupvarptr = Load(bcx, llupvarptr); } + alt mode { + for_block. { llupvarptr = Load(bcx, llupvarptr); } + for_send. | for_closure. { } + } let def_id = ast_util::def_id_of_def(upvar_def); fcx.llupvars.insert(def_id.node, llupvarptr); i += 1u; @@ -3532,7 +3564,8 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t, // Actually construct the closure let closure = build_environment(bcx, lltydescs, env_vals + - vec::map({|x| env_expr(x)}, bound), true); + vec::map({|x| env_expr(x)}, bound), + for_closure); bcx = closure.bcx; // Make thunk diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index 1e65d701e8f..889b5f62018 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -279,6 +279,8 @@ struct type_desc { const type_desc *descs[]; }; +extern "C" type_desc *rust_clone_type_desc(type_desc*); + #include "circular_buffer.h" #include "rust_task.h" #include "rust_port.h" diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 811a6b36df0..d91e282d2e2 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -195,6 +195,39 @@ upcall_shared_free(void* ptr) { SWITCH_STACK(&args, upcall_s_shared_free); } +struct s_clone_type_desc_args { + const type_desc *td; + type_desc *res; +}; + +void upcall_s_clone_type_desc(s_clone_type_desc_args *args) +{ + // Copy the main part of the type descriptor: + const type_desc *td = args->td; + int n_descs = td->n_descs; + size_t sz = sizeof(type_desc) + sizeof(type_desc*) * n_descs; + args->res = (type_desc*) malloc(sz); + memcpy(args->res, td, sizeof(type_desc)); + + // Recursively copy any referenced descriptors: + for (int i = 0; i < n_descs; i++) { + s_clone_type_desc_args rec_args = { td->descs[i], 0 }; + upcall_s_clone_type_desc(&rec_args); + args->res->descs[i] = rec_args.res; + } +} + +/** + * Called to deep-clone type descriptors so they can be attached to a sendable + * function. Eventually this should perhaps move to a centralized hashtable. + */ +type_desc * +upcall_clone_type_desc(type_desc *td) { + s_clone_type_desc_args args = { td, 0 }; + SWITCH_STACK(&args, upcall_s_clone_type_desc); + return args.res; +} + struct s_get_type_desc_args { type_desc *retval; size_t size;