mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
parent
c73eb8ff51
commit
bd6b80c972
@ -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++
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user