rt: Get rid of the rethrow in upcall_fail

Throwing in upcall_fail ends up running lots of code in the red zone. To avoid
it we have the personality function figure out which stack it's on and switch
as needed.
This commit is contained in:
Brian Anderson 2011-12-18 16:59:49 -08:00
parent c73eb8ff51
commit bd6b80c972
3 changed files with 35 additions and 12 deletions

View File

@ -732,6 +732,17 @@ rust_task::record_stack_limit() {
extern "C" uintptr_t get_sp();
static bool
sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
// Not positive these bounds for sp are correct. I think that the first
// possible value for esp on a new stack is stk->end, which points to the
// address before the first value to be pushed onto a new stack. The last
// possible address we can push data to is stk->data. Regardless, there's
// so much slop at either end that we should never hit one of these
// boundaries.
return (uintptr_t)stk->data <= sp && sp <= stk->end;
}
/*
Called by landing pads during unwinding to figure out which
stack segment we are currently running on, delete the others,
@ -741,17 +752,21 @@ through __morestack).
void
rust_task::reset_stack_limit() {
uintptr_t sp = get_sp();
// Not positive these bounds for sp are correct.
// I think that the first possible value for esp on a new
// stack is stk->end, which points one word in front of
// the first work to be pushed onto a new stack.
while (sp <= (uintptr_t)stk->data || stk->end < sp) {
while (!sp_in_stk_seg(sp, stk)) {
del_stk(this, stk);
A(sched, stk != NULL, "Failed to find the current stack");
}
record_stack_limit();
}
/*
Returns true if we're currently running on the Rust stack
*/
bool
rust_task::on_rust_stack() {
return sp_in_stk_seg(get_sp(), stk);
}
//
// Local Variables:
// mode: C++

View File

@ -202,6 +202,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
void del_stack();
void record_stack_limit();
void reset_stack_limit();
bool on_rust_stack();
};
//

View File

@ -88,12 +88,8 @@ extern "C" CDECL void
upcall_fail(char const *expr,
char const *file,
size_t line) {
try {
s_fail_args args = {expr,file,line};
UPCALL_SWITCH_STACK(&args, upcall_s_fail);
} catch (rust_task*) {
throw;
}
s_fail_args args = {expr,file,line};
UPCALL_SWITCH_STACK(&args, upcall_s_fail);
}
/**********************************************************************
@ -536,7 +532,18 @@ upcall_rust_personality(int version,
s_rust_personality_args args = {(_Unwind_Reason_Code)0,
version, actions, exception_class,
ue_header, context};
UPCALL_SWITCH_STACK(&args, upcall_s_rust_personality);
rust_task *task = rust_scheduler::get_task();
// The personality function is run on the stack of the
// last function that threw or landed, which is going
// to sometimes be the C stack. If we're on the Rust stack
// then switch to the C stack.
if (task->on_rust_stack()) {
UPCALL_SWITCH_STACK(&args, upcall_s_rust_personality);
} else {
upcall_s_rust_personality(&args);
}
return args.retval;
}