Split start into rustc and rustboot versions. This introduces a bit of

duplication, but we will hopefully drop the rustboot one soon.

This is also a preparation for changing the rustc one to have the activate glue
return to the exit glue which will then call the main function.

This (returning to the function that calls main) matches what happens when
loader stats a program or a new thread. It lets gdb produce good backtraces
and should help with EH too.
This commit is contained in:
Rafael Ávila de Espíndola
2011-05-03 10:19:28 -04:00
parent a919a3082d
commit a3ff02f126
2 changed files with 122 additions and 27 deletions

View File

@@ -141,6 +141,18 @@ rust_task::start(uintptr_t exit_task_glue,
uintptr_t spawnee_fn,
uintptr_t args,
size_t callsz)
{
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
start_rustboot(exit_task_glue, spawnee_fn, args, callsz);
else
start_rustc(exit_task_glue, spawnee_fn, args, callsz);
}
void
rust_task::start_rustboot(uintptr_t exit_task_glue,
uintptr_t spawnee_fn,
uintptr_t args,
size_t callsz)
{
LOGPTR(dom, "exit-task glue", exit_task_glue);
LOGPTR(dom, "from spawnee", spawnee_fn);
@@ -176,30 +188,25 @@ rust_task::start(uintptr_t exit_task_glue,
uintptr_t exit_task_frame_base = 0;
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
for (size_t j = 0; j < n_callee_saves; ++j) {
for (size_t j = 0; j < n_callee_saves; ++j) {
// We want 'frame_base' to point to the old fp in this (exit-task)
// frame, because we're going to inject this frame-pointer into
// the callee-save frame pointer value in the *next* (spawnee)
// frame. A cheap trick, but this means the spawnee frame will
// restore the proper frame pointer of the glue frame as it runs
// its epilogue.
if (j == callee_save_fp)
exit_task_frame_base = (uintptr_t)spp;
// We want 'frame_base' to point to the old fp in this (exit-task)
// frame, because we're going to inject this frame-pointer into
// the callee-save frame pointer value in the *next* (spawnee)
// frame. A cheap trick, but this means the spawnee frame will
// restore the proper frame pointer of the glue frame as it runs
// its epilogue.
if (j == callee_save_fp)
exit_task_frame_base = (uintptr_t)spp;
*spp-- = 0;
}
*spp-- = (uintptr_t) dom->root_crate; // crate ptr
*spp-- = (uintptr_t) 0; // frame_glue_fns
*spp-- = 0;
}
*spp-- = (uintptr_t) dom->root_crate; // crate ptr
*spp-- = (uintptr_t) 0; // frame_glue_fns
I(dom, args);
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
make_aligned_room_for_bytes(spp, callsz - sizeof(uintptr_t));
else
make_aligned_room_for_bytes(spp, callsz - 3 * sizeof(uintptr_t));
make_aligned_room_for_bytes(spp, callsz - sizeof(uintptr_t));
// Copy args from spawner to spawnee.
uintptr_t *src = (uintptr_t *)args;
@@ -222,16 +229,96 @@ rust_task::start(uintptr_t exit_task_glue,
// activating:
*spp-- = (uintptr_t) 0x0; // closure-or-obj
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
// in CDECL mode we write the task + outptr to the spawnee stack.
*spp-- = (uintptr_t) this; // task
*spp-- = (uintptr_t) 0; // output addr
} else {
// 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.
I(dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
// in CDECL mode we write the task + outptr to the spawnee stack.
*spp-- = (uintptr_t) this; // task
*spp-- = (uintptr_t) 0; // output addr
I(dom, spp+1 == align_down(spp+1));
*spp-- = (uintptr_t) exit_task_glue; // retpc
// 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) {
// callee-saves to carry in when we activate
if (j == callee_save_fp)
*spp-- = exit_task_frame_base;
else
*spp-- = (uintptr_t)NULL;
}
// Back up one, we overshot where sp should be.
rust_sp = (uintptr_t) (spp+1);
transition(&dom->newborn_tasks, &dom->running_tasks);
}
void
rust_task::start_rustc(uintptr_t exit_task_glue,
uintptr_t spawnee_fn,
uintptr_t args,
size_t callsz)
{
LOGPTR(dom, "exit-task glue", exit_task_glue);
LOGPTR(dom, "from spawnee", spawnee_fn);
// Set sp to last uintptr_t-sized cell of segment
rust_sp -= sizeof(uintptr_t);
// NB: Darwin needs "16-byte aligned" stacks *at the point of the call
// instruction in the caller*. This means that the address at which the
// word before 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
// 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.
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, 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 exit_task_frame_base = 0;
I(dom, args);
make_aligned_room_for_bytes(spp, callsz - 3 * sizeof(uintptr_t));
// Copy args from spawner to spawnee.
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;
// 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--;
// The *implicit* incoming args to the spawnee frame we're
// activating:
*spp-- = (uintptr_t) 0x0; // closure-or-obj
// 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.
I(dom, spp+1 == align_down(spp+1));
*spp-- = (uintptr_t) exit_task_glue; // retpc