提交 bd6b80c9 编写于 作者: B Brian Anderson

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.
上级 c73eb8ff
...@@ -732,6 +732,17 @@ rust_task::record_stack_limit() { ...@@ -732,6 +732,17 @@ rust_task::record_stack_limit() {
extern "C" uintptr_t get_sp(); 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 Called by landing pads during unwinding to figure out which
stack segment we are currently running on, delete the others, stack segment we are currently running on, delete the others,
...@@ -741,17 +752,21 @@ through __morestack). ...@@ -741,17 +752,21 @@ through __morestack).
void void
rust_task::reset_stack_limit() { rust_task::reset_stack_limit() {
uintptr_t sp = get_sp(); uintptr_t sp = get_sp();
// Not positive these bounds for sp are correct. while (!sp_in_stk_seg(sp, stk)) {
// 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) {
del_stk(this, stk); del_stk(this, stk);
A(sched, stk != NULL, "Failed to find the current stack"); A(sched, stk != NULL, "Failed to find the current stack");
} }
record_stack_limit(); 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: // Local Variables:
// mode: C++ // mode: C++
......
...@@ -202,6 +202,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond ...@@ -202,6 +202,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
void del_stack(); void del_stack();
void record_stack_limit(); void record_stack_limit();
void reset_stack_limit(); void reset_stack_limit();
bool on_rust_stack();
}; };
// //
......
...@@ -88,12 +88,8 @@ extern "C" CDECL void ...@@ -88,12 +88,8 @@ extern "C" CDECL void
upcall_fail(char const *expr, upcall_fail(char const *expr,
char const *file, char const *file,
size_t line) { size_t line) {
try { s_fail_args args = {expr,file,line};
s_fail_args args = {expr,file,line}; UPCALL_SWITCH_STACK(&args, upcall_s_fail);
UPCALL_SWITCH_STACK(&args, upcall_s_fail);
} catch (rust_task*) {
throw;
}
} }
/********************************************************************** /**********************************************************************
...@@ -536,7 +532,18 @@ upcall_rust_personality(int version, ...@@ -536,7 +532,18 @@ upcall_rust_personality(int version,
s_rust_personality_args args = {(_Unwind_Reason_Code)0, s_rust_personality_args args = {(_Unwind_Reason_Code)0,
version, actions, exception_class, version, actions, exception_class,
ue_header, context}; 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; return args.retval;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册