From bd6b80c9720bb4b0143378a052b568697ce3abe6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 18 Dec 2011 16:59:49 -0800 Subject: [PATCH] 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. --- src/rt/rust_task.cpp | 25 ++++++++++++++++++++----- src/rt/rust_task.h | 1 + src/rt/rust_upcall.cpp | 21 ++++++++++++++------- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index f74f821819c0..f30315174b6f 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -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++ diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 3339ad42bfdd..51ae00a6b707 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -202,6 +202,7 @@ rust_task : public kernel_owned, rust_cond void del_stack(); void record_stack_limit(); void reset_stack_limit(); + bool on_rust_stack(); }; // diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 506441979cac..5febc5098a21 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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; }