get basic code generation working, clone type descs for lambda[send]

This commit is contained in:
Niko Matsakis 2011-12-11 20:42:37 -08:00
parent 36177dd3e9
commit 6a8cb704d9
4 changed files with 113 additions and 33 deletions

View File

@ -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", [])
};
}
//

View File

@ -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

View File

@ -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"

View File

@ -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;