Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spawn Work #401

Merged
merged 9 commits into from
May 27, 2011
2 changes: 1 addition & 1 deletion src/comp/back/upcall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
175 changes: 100 additions & 75 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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));
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/rt/rust_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 11 additions & 7 deletions src/rt/rust_upcall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
14 changes: 10 additions & 4 deletions src/test/run-pass/spawn.rs
Original file line number Diff line number Diff line change
@@ -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:
36 changes: 36 additions & 0 deletions src/test/run-pass/spawn2.rs
Original file line number Diff line number Diff line change
@@ -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: