diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 3a654da8ae6ca..bc216b4348858 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -7074,14 +7074,25 @@ fn trans_exit_task_glue(@glue_fns glues, let vec[ValueRef] V_args = vec(); auto llfn = glues.exit_task_glue; - let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 4u); auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry")); auto build = new_builder(entrybb); - auto tptr = build.PtrToInt(lltaskptr, T_int()); - auto V_args2 = vec(tptr) + V_args; - trans_native_call(build, glues, lltaskptr, - externs, tn, llmod, "upcall_exit", true, V_args2); + + let ValueRef arg1 = llvm.LLVMGetParam(llfn, 0u); + let ValueRef arg2 = llvm.LLVMGetParam(llfn, 1u); + let ValueRef arg3 = llvm.LLVMGetParam(llfn, 2u); + let ValueRef arg4 = llvm.LLVMGetParam(llfn, 3u); + let ValueRef arg5 = llvm.LLVMGetParam(llfn, 4u); + + auto main_type = T_fn(vec(T_int(), T_int(), T_int(), T_int()), T_void()); + + auto fun = build.IntToPtr(arg1, T_ptr(main_type)); + auto call_args = vec(arg2, arg3, arg4, arg5); + build.FastCall(fun, call_args); + + trans_native_call(build, glues, arg3, + externs, tn, llmod, "upcall_exit", true, vec(arg3)); + build.RetVoid(); } @@ -7679,22 +7690,12 @@ fn trans_vec_append_glue(@local_ctxt cx) { fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns { ret @rec(activate_glue = decl_glue(llmod, tn, abi.activate_glue_name()), yield_glue = decl_glue(llmod, tn, abi.yield_glue_name()), - /* - * Note: the signature passed to decl_cdecl_fn here looks unusual - * because it is. It corresponds neither to a native signature - * nor a normal rust-ABI signature. In fact it is a fake - * signature, that exists solely to acquire the task pointer as - * an argument to the upcall. It so happens that the runtime sets - * up the task pointer as the sole incoming argument to the frame - * that we return into when returning to the exit task glue. So - * this is the signature required to retrieve it. - */ exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(), T_fn(vec(T_int(), T_int(), T_int(), T_int(), - T_taskptr(tn)), + T_int()), T_void())), native_glues_rust = diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 3f4c89d894807..ab75798817c20 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -254,9 +254,9 @@ rust_task::start_rustboot(uintptr_t exit_task_glue, void rust_task::start_rustc(uintptr_t exit_task_glue, - uintptr_t spawnee_fn, - uintptr_t args, - size_t callsz) + uintptr_t spawnee_fn, + uintptr_t args, + size_t callsz) { LOGPTR(dom, "exit-task glue", exit_task_glue); LOGPTR(dom, "from spawnee", spawnee_fn); @@ -271,27 +271,18 @@ rust_task::start_rustc(uintptr_t exit_task_glue, // see: "Mac OS X ABI Function Call Guide" - // Begin synthesizing frames. There are two: a "fully formed" - // exit-task frame at the top of the stack -- that pretends to be - // mid-execution -- and a just-starting frame beneath it that - // starts executing the first instruction of the spawnee. The - // spawnee *thinks* it was called by the exit-task frame above - // it. It wasn't; we put that fake frame in place here, but the - // illusion is enough for the spawnee to return to the exit-task - // frame when it's done, and exit. + // Begin synthesizing the exit_task_glue frame. We will return to + // exit_task_glue and it is responsible for calling the user code + // and passing the value returned by the user to the system + // exit routine. uintptr_t *spp = (uintptr_t *)rust_sp; + uintptr_t dummy_ret = (uintptr_t) spp--; - // The exit_task_glue frame we synthesize above the frame we activate: - make_aligned_room_for_bytes(spp, 2 * sizeof(uintptr_t)); - *spp-- = (uintptr_t) 0; // closure-or-obj - *spp-- = (uintptr_t) this; // task - I(dom, spp == align_down(spp)); - *spp-- = (uintptr_t) 0x0; // output - *spp-- = (uintptr_t) 0x0; // retpc + uintptr_t args_size = callsz - 3*sizeof(uintptr_t); + uintptr_t frame_size = args_size + 4*sizeof(uintptr_t); - I(dom, args); - make_aligned_room_for_bytes(spp, callsz - 3 * sizeof(uintptr_t)); + make_aligned_room_for_bytes(spp, frame_size); // Copy args from spawner to spawnee. uintptr_t *src = (uintptr_t *)args; @@ -299,29 +290,19 @@ rust_task::start_rustc(uintptr_t exit_task_glue, src += 1; // spawn-call task slot src += 1; // spawn-call closure-or-obj slot - // Undo previous sp-- so we're pointing at the last word pushed. - ++spp; - - // Memcpy all but the task, output and env pointers - callsz -= (3 * sizeof(uintptr_t)); - spp = (uintptr_t*) (((uintptr_t)spp) - callsz); - memcpy(spp, src, callsz); + *spp-- = (uintptr_t) *src; // vec + *spp-- = (uintptr_t) 0x0; // closure-or-obj + *spp-- = (uintptr_t) this; // task + *spp-- = (uintptr_t) dummy_ret; // output address - // Move sp down to point to last implicit-arg cell (env). - spp--; + *spp-- = (uintptr_t) (uintptr_t) spawnee_fn; - // The *implicit* incoming args to the spawnee frame we're - // activating: - *spp-- = (uintptr_t) 0x0; // closure-or-obj + I(dom, spp == align_down(spp)); - // in FASTCALL mode we don't, the outptr will be in ecx and the task - // in edx, and the activate_glue will make sure to set that up. + *spp-- = (uintptr_t) 0x0; // retp - I(dom, spp+1 == align_down(spp+1)); - *spp-- = (uintptr_t) exit_task_glue; // retpc + *spp-- = (uintptr_t) exit_task_glue; - // The context the activate_glue needs to switch stack. - *spp-- = (uintptr_t) spawnee_fn; // instruction to start at for (size_t j = 0; j < n_callee_saves; ++j) { *spp-- = (uintptr_t)NULL; }