From d49998f0ed9b0a239b40d30ccfde750f8439cac4 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 26 May 2011 18:00:33 -0700 Subject: [PATCH] Switching over to wrappers for spawning functions of multiple arguments. Doesn't quite work yet. --- src/comp/back/upcall.rs | 2 +- src/comp/middle/trans.rs | 154 ++++++++++++++++++++++++++---------- src/rt/rust_task.cpp | 7 +- src/rt/rust_upcall.cpp | 18 +++-- src/test/run-pass/spawn.rs | 8 ++ src/test/run-pass/spawn2.rs | 33 +++++++- 6 files changed, 163 insertions(+), 59 deletions(-) diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index f05ea3d75762..e80100cc55d6 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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(), diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 069e5bdb2580..9f3d4b8b3b31 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index e18259fba607..b23da1b12846 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -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 diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index b0c362ecc7a6..966ddb15eee5 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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; } diff --git a/src/test/run-pass/spawn.rs b/src/test/run-pass/spawn.rs index 7bc2cbc3dd8a..dcee95ada00d 100644 --- a/src/test/run-pass/spawn.rs +++ b/src/test/run-pass/spawn.rs @@ -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: diff --git a/src/test/run-pass/spawn2.rs b/src/test/run-pass/spawn2.rs index f5a0e8f28950..13da73db36e6 100644 --- a/src/test/run-pass/spawn2.rs +++ b/src/test/run-pass/spawn2.rs @@ -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: