diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index f05ea3d75762c..e80100cc55d6f 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 9c3f5178fec19..5cb1487925373 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)); @@ -760,6 +760,9 @@ fn type_of_inner(&@crate_ctxt cx, &ast::span sp, &ty::t t) -> TypeRef { case (ty::ty_chan(?t)) { llty = T_ptr(T_chan(type_of_inner(cx, sp, t))); } + case (ty::ty_task) { + llty = T_taskptr(cx.tn); + } case (ty::ty_tup(?elts)) { let vec[TypeRef] tys = []; for (ty::mt elt in elts) { @@ -2014,6 +2017,11 @@ fn make_free_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) { rslt = res(cx, C_int(0)); } + case (ty::ty_task) { + // TODO: call upcall_kill + rslt = res(cx, C_nil()); + } + case (ty::ty_obj(_)) { auto box_cell = @@ -2107,6 +2115,10 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); } + case (ty::ty_task) { + rslt = decr_refcnt_maybe_free(cx, v0, v0, t); + } + case (ty::ty_obj(_)) { auto box_cell = cx.build.GEP(v0, @@ -5843,11 +5855,6 @@ fn trans_spawn(&@block_ctxt cx, } }; - // dump a bunch of information - log_err "Translating Spawn " + - "(The compiled program is not actually running yet, don't worry!"; - log_err #fmt("task name: %s", tname); - // Generate code // // This is a several step process. The following things need to happen @@ -5860,35 +5867,37 @@ 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. + 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, e)); } - // Make the tuple. We have to reverse the types first though. - vec::reverse[ty::t](arg_tys); - vec::reverse[ValueRef](arg_vals); + // Make the tuple. auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys); // Allocate and fill the tuple. auto llargs = alloc_ty(bcx, args_ty); - auto i = vec::len[ValueRef](arg_vals) - 1u; + auto i = 0u; for(ValueRef v in arg_vals) { // log_err #fmt("ty(llargs) = %s", // val_str(bcx.fcx.lcx.ccx.tn, llargs.val)); @@ -5900,86 +5909,102 @@ fn trans_spawn(&@block_ctxt cx, bcx.build.Store(v, target); - i -= 1u; + i += 1u; } // Now we're ready to do the upcall. // But first, we'll create a task. let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname); - log_err #fmt("ty(new_task) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - bcx.fcx.lcx.ccx.upcalls.new_task)); - log_err #fmt("ty(lltaskptr) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - bcx.fcx.lltaskptr)); - log_err #fmt("ty(lltname) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - lltname)); - - log_err "Building upcall_new_task"; auto new_task = bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task, [bcx.fcx.lltaskptr, lltname]); - log_err "Done"; // Okay, start the task. - // First we find the function - auto fnptr = trans_lval(bcx, func).res; - bcx = fnptr.bcx; - - auto num_args = vec::len[@ast::expr](args); - - auto llfnptr = bcx.build.GEP(fnptr.val, - [C_int(0), C_int(0)]); - log_err "Casting llfnptr"; - auto llfnptr_i = bcx.build.PointerCast(llfnptr, - T_int()); - log_err "Cassting llargs"; + auto llargs_i = bcx.build.PointerCast(llargs.val, - T_int()); - - log_err "Building call to start_task"; - log_err #fmt("ty(start_task) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - bcx.fcx.lcx.ccx.upcalls.start_task)); - log_err #fmt("ty(lltaskptr) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - bcx.fcx.lltaskptr)); - log_err #fmt("ty(new_task) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - new_task)); - log_err #fmt("ty(llfnptr) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - llfnptr_i)); - log_err #fmt("ty(llargs) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - llargs_i)); - log_err #fmt("ty(num_args) = %s", - val_str(bcx.fcx.lcx.ccx.tn, - C_int(num_args as int))); + T_int()); + + // Generate the wrapper function + auto wrapper = mk_spawn_wrapper(bcx, 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, C_int(num_args as int)]); - log_err "Done"; + llfnptr_i, llargs_i]); - /* - alt(dom) { - case(ast::dom_implicit) { - // TODO - log_err "Spawning implicit domain tasks is not implemented."; - //fail; - } + auto task_ty = node_ann_type(bcx.fcx.lcx.ccx, ann); + auto dropref = clean(bind drop_ty(_, new_task, task_ty)); + find_scope_cx(bcx).cleanups += [dropref]; - case(ast::dom_thread) { - // TODO - log_err "Spawining new thread tasks is not implemented."; - // TODO: for now use the normal unimpl thing. - fail; + ret res(bcx, new_task); +} + +fn mk_spawn_wrapper(&@block_ctxt cx, + &@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 = + type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn, + [rec(mode = ty::mo_alias, ty = args_ty)], + ty::idx_nil, + 0u); + + // TODO: construct a name based on tname + let str wrap_name = mangle_name_by_seq(cx.fcx.lcx.ccx, + [""], + "spawn_wrapper"); + auto llfndecl = decl_fastcall_fn(llmod, wrap_name, + wrapper_fn_type); + + auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl); + + auto fbcx = new_top_block_ctxt(fcx); + + // 3u to skip the three implicit args + let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u); + + 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) { + auto src = fbcx.build.GEP(arg, [C_int(0), C_int(i)]); + i += 1; + + auto child_arg = fbcx.build.Load(src); + + child_args += [child_arg]; + } } } - */ + + // Find the function + auto fnptr = trans_lval(fbcx, func).res; + fbcx = fnptr.bcx; + + auto llfnptr = fbcx.build.GEP(fnptr.val, + [C_int(0), C_int(0)]); + auto llfn = fbcx.build.Load(llfnptr); + + fbcx.build.FastCall(llfn, + child_args); + fbcx.build.RetVoid(); + + finish_fn(fcx, fbcx.llbb); - ret res(bcx, new_task); + // 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, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 508b2d90a63e2..3d12d16d5284d 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -951,6 +951,7 @@ fn type_is_boxed(&ctxt cx, &t ty) -> bool { case (ty_box(_)) { ret true; } case (ty_port(_)) { ret true; } case (ty_chan(_)) { ret true; } + case (ty_task) { ret true; } case (_) { ret false; } } fail; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index e937bd42ffca0..b23da1b128468 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -179,7 +179,6 @@ rust_task::start(uintptr_t spawnee_fn, I(dom, spp == align_down(spp)); *spp-- = (uintptr_t) (uintptr_t) spawnee_fn; - *spp-- = (uintptr_t) 0x0; // retp *spp-- = (uintptr_t) rust_new_exit_task_glue; diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index b0c362ecc7a6c..6d8734bd43008 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 ba554fdaf17a0..6978326d9b1e6 100644 --- a/src/test/run-pass/spawn.rs +++ b/src/test/run-pass/spawn.rs @@ -1,13 +1,19 @@ // xfail-stage0 -// xfail-stage1 -// xfail-stage2 // -*- rust -*- fn main() { - spawn child(10); + auto t = spawn child(10); } fn child(int i) { - log 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 new file mode 100644 index 0000000000000..13da73db36e6a --- /dev/null +++ b/src/test/run-pass/spawn2.rs @@ -0,0 +1,36 @@ +// xfail-stage0 +// -*- rust -*- + +fn main() { + spawn child(10, 20, 30, 40, 50, 60, 70, 80, 90); +} + +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: