Ensure task stacks start out with a 16-byte aligned entry frame. Should make OSX behave a bit better.

This commit is contained in:
Graydon Hoare 2011-03-30 13:04:18 -07:00
parent b5a4336487
commit 3e7b991d49
2 changed files with 47 additions and 20 deletions

View File

@ -6272,7 +6272,7 @@ 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, 3u);
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 4u);
auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
auto build = new_builder(entrybb);
@ -6731,6 +6731,7 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
*/
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)),

View File

@ -58,6 +58,21 @@ align_down(uintptr_t sp)
return sp & ~(16 - 1);
}
static uintptr_t*
align_down(uintptr_t* sp)
{
return (uintptr_t*) align_down((uintptr_t)sp);
}
static void
make_aligned_room_for_bytes(uintptr_t*& sp, size_t n)
{
uintptr_t tmp = (uintptr_t) sp;
tmp = align_down(tmp - n) + n;
sp = (uintptr_t*) tmp;
}
rust_task::rust_task(rust_dom *dom, rust_task_list *state,
rust_task *spawner, const char *name) :
@ -131,9 +146,15 @@ rust_task::start(uintptr_t exit_task_glue,
dom->logptr("exit-task glue", exit_task_glue);
dom->logptr("from spawnee", spawnee_fn);
// Set sp to last uintptr_t-sized cell of segment and align down.
// Set sp to last uintptr_t-sized cell of segment
rust_sp -= sizeof(uintptr_t);
rust_sp = align_down(rust_sp);
// NB: Darwin needs "16-byte aligned" stacks *at the point of the call
// instruction in the caller*. This means that the address at which a
// retpc is pushed must always be 16-byte aligned.
//
// 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
@ -145,10 +166,13 @@ rust_task::start(uintptr_t exit_task_glue,
// frame when it's done, and exit.
uintptr_t *spp = (uintptr_t *)rust_sp;
// The exit_task_glue frame we synthesize above the frame we activate:
make_aligned_room_for_bytes(spp, 3 * sizeof(uintptr_t));
*spp-- = (uintptr_t) 0; // closure-or-obj
*spp-- = (uintptr_t) this; // task
*spp-- = (uintptr_t) 0x0; // output
I(dom, spp == align_down(spp));
*spp-- = (uintptr_t) 0x0; // retpc
uintptr_t exit_task_frame_base;
@ -172,27 +196,28 @@ rust_task::start(uintptr_t exit_task_glue,
*spp-- = (uintptr_t) 0; // frame_glue_fns
}
I(dom, args);
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
make_aligned_room_for_bytes(spp, callsz);
else
make_aligned_room_for_bytes(spp, callsz - 2 * sizeof(uintptr_t));
// Copy args from spawner to spawnee.
if (args) {
uintptr_t *src = (uintptr_t *)args;
src += 1; // spawn-call output slot
src += 1; // spawn-call task slot
src += 1; // spawn-call closure-or-obj slot
uintptr_t *src = (uintptr_t *)args;
src += 1; // spawn-call output slot
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;
// 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);
// 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);
// Move sp down to point to last implicit-arg cell (env).
spp--;
} else {
// We're at root, starting up.
I(dom, callsz==0);
}
// Move sp down to point to last implicit-arg cell (env).
spp--;
// The *implicit* incoming args to the spawnee frame we're
// activating:
@ -208,6 +233,7 @@ rust_task::start(uintptr_t exit_task_glue,
I(dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
}
I(dom, spp == align_down(spp));
*spp-- = (uintptr_t) exit_task_glue; // retpc
// The context the activate_glue needs to switch stack.