Switching over to wrappers for spawning functions of multiple arguments. Doesn't quite work yet.

This commit is contained in:
Eric Holk 2011-05-26 18:00:33 -07:00
parent 842bf7cad1
commit d49998f0ed
6 changed files with 163 additions and 59 deletions

View file

@ -113,7 +113,7 @@ fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
T_ptr(T_tydesc(tn))),
new_task=d("new_task", [T_ptr(T_str())], T_taskptr(tn)),
start_task=d("start_task", [T_taskptr(tn),
T_int(), T_int(), T_size_t()],
T_int(), T_int()],
T_taskptr(tn)),
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
start_thread=d("start_thread", [T_taskptr(tn), T_int(), T_int(),

View file

@ -601,7 +601,7 @@ fn type_of_explicit_args(&@crate_ctxt cx, &ast::span sp,
assert (arg.mode == ty::mo_alias);
atys += [T_typaram_ptr(cx.tn)];
} else {
let TypeRef t;
let TypeRef t;
alt (arg.mode) {
case (ty::mo_alias) {
t = T_ptr(type_of_inner(cx, sp, arg.ty));
@ -5867,22 +5867,24 @@ fn trans_spawn(&@block_ctxt cx,
//
// 3. Fill the tuple with the arguments we evaluated.
//
// 4. Pass a pointer to the spawnee function and the argument tuple to
// upcall_start_task.
// 3.5. Generate a wrapper function that takes the tuple and unpacks it to
// call the real task.
//
// 4. Pass a pointer to the wrapper function and the argument tuple to
// upcall_start_task. In order to do this, we need to allocate another
// tuple that matches the arguments expected by rust_task::start.
//
// 5. Oh yeah, we have to create the task before we start it...
// Translate the arguments, remembering their types and where the values
// ended up.
// There are 3 integers, for magic.
let vec[ty::t] arg_tys = [ty::idx_int, ty::idx_int, ty::idx_int];
let vec[ty::t] arg_tys = [];
let vec[ValueRef] arg_vals = [];
for(@ast::expr e in args) {
auto arg = trans_expr(bcx, e);
bcx = arg.bcx;
vec::push[ValueRef](arg_vals, arg.val);
vec::push[ty::t](arg_tys,
ty::expr_ty(cx.fcx.lcx.ccx.tcx,
@ -5895,8 +5897,7 @@ fn trans_spawn(&@block_ctxt cx,
// Allocate and fill the tuple.
auto llargs = alloc_ty(bcx, args_ty);
// 3 to skip all the magic
auto i = 3u;
auto i = 0u;
for(ValueRef v in arg_vals) {
// log_err #fmt("ty(llargs) = %s",
// val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
@ -5919,45 +5920,21 @@ fn trans_spawn(&@block_ctxt cx,
[bcx.fcx.lltaskptr, lltname]);
// Okay, start the task.
// First we find the function
auto fnptr = trans_lval(bcx, func).res;
bcx = fnptr.bcx;
auto llfnptr = bcx.build.GEP(fnptr.val,
[C_int(0), C_int(0)]);
log_err "Casting llfnptr";
auto llfnptrptr_i = bcx.build.PointerCast(llfnptr,
T_ptr(T_int()));
// We'd better dereference this one more time, since that one points into
// the symbol table or something.
auto llfnptr_i = bcx.build.Load(llfnptrptr_i);
log_err "Cassting llargs";
auto llargs_i = bcx.build.PointerCast(llargs.val,
T_int());
T_int());
auto args_size = size_of(bcx, args_ty).val;
// Generate the wrapper function
auto wrapper = mk_spawn_wrapper(bcx, tname, func, args_ty);
bcx = wrapper.bcx;
auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());
// TODO: this next line might be necessary...
//llfnptr_i = bcx.build.Load(llfnptr_i);
// And start the task
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
[bcx.fcx.lltaskptr, new_task,
llfnptr_i, llargs_i, args_size]);
/*
alt(dom) {
case(ast::dom_implicit) {
// TODO
log_err "Spawning implicit domain tasks is not implemented.";
//fail;
}
case(ast::dom_thread) {
// TODO
log_err "Spawining new thread tasks is not implemented.";
// TODO: for now use the normal unimpl thing.
fail;
}
}
*/
llfnptr_i, llargs_i]);
auto task_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
auto dropref = clean(bind drop_ty(_, new_task, task_ty));
@ -5966,6 +5943,101 @@ fn trans_spawn(&@block_ctxt cx,
ret res(bcx, new_task);
}
fn mk_spawn_wrapper(&@block_ctxt cx,
&str tname,
&@ast::expr func,
&ty::t args_ty) -> result {
auto llmod = cx.fcx.lcx.ccx.llmod;
let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty);
//let TypeRef wrapper_fn_type = T_fn([args_ty_tref], T_void());
let TypeRef wrapper_fn_type =
type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn,
[rec(mode = ty::mo_alias, ty = args_ty)],
ty::idx_nil,
0u);
log_err #fmt("wrapper args type: %s",
ty_str(cx.fcx.lcx.ccx.tn, args_ty_tref));
log_err #fmt("wrapper fn desired type: %s",
ty_str(cx.fcx.lcx.ccx.tn, wrapper_fn_type));
// TODO: construct a name based on tname
auto llfndecl = decl_cdecl_fn(llmod, "spawn_wrap",
wrapper_fn_type);
log_err #fmt("spawn wrapper decl type: %s",
val_str(cx.fcx.lcx.ccx.tn, llfndecl));
auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl);
auto fbcx = new_top_block_ctxt(fcx);
log_err #fmt("spawn wrapper type: %s", val_str(fcx.lcx.ccx.tn,
fcx.llfn));
// 3u to skip the three implicit args
let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
log_err #fmt("arg type: %s", val_str(fbcx.fcx.lcx.ccx.tn, arg));
let vec[ValueRef] child_args =
[llvm::LLVMGetParam(fcx.llfn, 0u),
llvm::LLVMGetParam(fcx.llfn, 1u),
llvm::LLVMGetParam(fcx.llfn, 2u)];
// unpack the arguments
alt(ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
case(ty::ty_tup(?elements)) {
auto i = 0;
for(ty::mt m in elements) {
log_err #fmt("GEP arg %d", i);
auto src = fbcx.build.GEP(arg, [C_int(0), C_int(i)]);
i += 1;
log_err #fmt("generating load of type %s",
val_str(fbcx.fcx.lcx.ccx.tn,
src));
auto child_arg = fbcx.build.Load(src);
child_args += [child_arg];
}
}
}
// Find the function
auto fnptr = trans_lval(fbcx, func).res;
fbcx = fnptr.bcx;
log_err "SPAWN 1";
auto llfnptr = fbcx.build.GEP(fnptr.val,
[C_int(0), C_int(0)]);
auto llfn = fbcx.build.Load(llfnptr);
log_err #fmt("Generating call to child function: %s",
val_str(fbcx.fcx.lcx.ccx.tn,
llfn));
auto i = 0;
for(ValueRef v in child_args) {
log_err #fmt("Arg %d: %s",
i,
val_str(fbcx.fcx.lcx.ccx.tn,
v));
i += 1;
}
fbcx.build.Call(llfn,
child_args);
fbcx.build.RetVoid();
finish_fn(fcx, fbcx.llbb);
// TODO: make sure we clean up everything we need to.
ret res(cx, llfndecl);
}
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
&ast::ann ann) -> result {
auto bcx = cx;

View file

@ -171,12 +171,7 @@ rust_task::start(uintptr_t spawnee_fn,
src += 1; // spawn-call task slot
src += 1; // spawn-call closure-or-obj slot
spp -= (args_size / sizeof(uintptr_t)) - 1;
memmove(spp, src, args_size);
spp--;
//*spp-- = (uintptr_t) *src; // vec
*spp-- = (uintptr_t) *src; // vec
*spp-- = (uintptr_t) 0x0; // closure-or-obj
*spp-- = (uintptr_t) this; // task
*spp-- = (uintptr_t) dummy_ret; // output address

View file

@ -466,17 +466,21 @@ extern "C" CDECL rust_task *
upcall_start_task(rust_task *spawner,
rust_task *task,
uintptr_t spawnee_fn,
uintptr_t args,
size_t callsz) {
uintptr_t args) {
LOG_UPCALL_ENTRY(spawner);
rust_dom *dom = spawner->dom;
DLOG(dom, task,
"upcall start_task(task %s @0x%" PRIxPTR
", spawnee 0x%" PRIxPTR
", callsz %" PRIdPTR ")", task->name, task,
spawnee_fn, callsz);
task->start(spawnee_fn, args, callsz);
"upcall start_task(task %s @0x%" PRIxPTR
", spawnee 0x%" PRIxPTR ")",
task->name, task,
spawnee_fn);
// we used to be generating this tuple in rustc, but it's easier to do it
// here.
uintptr_t start_args[] = {0, 0, 0, args};
task->start(spawnee_fn, (uintptr_t)&start_args, sizeof(start_args));
return task;
}

View file

@ -9,3 +9,11 @@ fn child(int i) {
log_err i;
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:

View file

@ -2,10 +2,35 @@
// -*- rust -*-
fn main() {
spawn child(10, 20);
spawn child(10, 20, 30, 40, 50, 60, 70, 80, 90);
}
fn child(int i, int j) {
log_err i;
log_err j;
fn child(int i1,
int i2,
int i3,
int i4,
int i5,
int i6,
int i7,
int i8,
int i9)
{
log_err i1;
log_err i2;
log_err i3;
log_err i4;
log_err i5;
log_err i6;
log_err i7;
log_err i8;
log_err i9;
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End: