Skip to content

Commit bd6b80c

Browse files
committed
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.
1 parent c73eb8f commit bd6b80c

File tree

3 files changed

+35
-12
lines changed

3 files changed

+35
-12
lines changed

src/rt/rust_task.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,17 @@ rust_task::record_stack_limit() {
732732

733733
extern "C" uintptr_t get_sp();
734734

735+
static bool
736+
sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
737+
// Not positive these bounds for sp are correct. I think that the first
738+
// possible value for esp on a new stack is stk->end, which points to the
739+
// address before the first value to be pushed onto a new stack. The last
740+
// possible address we can push data to is stk->data. Regardless, there's
741+
// so much slop at either end that we should never hit one of these
742+
// boundaries.
743+
return (uintptr_t)stk->data <= sp && sp <= stk->end;
744+
}
745+
735746
/*
736747
Called by landing pads during unwinding to figure out which
737748
stack segment we are currently running on, delete the others,
@@ -741,17 +752,21 @@ through __morestack).
741752
void
742753
rust_task::reset_stack_limit() {
743754
uintptr_t sp = get_sp();
744-
// Not positive these bounds for sp are correct.
745-
// I think that the first possible value for esp on a new
746-
// stack is stk->end, which points one word in front of
747-
// the first work to be pushed onto a new stack.
748-
while (sp <= (uintptr_t)stk->data || stk->end < sp) {
755+
while (!sp_in_stk_seg(sp, stk)) {
749756
del_stk(this, stk);
750757
A(sched, stk != NULL, "Failed to find the current stack");
751758
}
752759
record_stack_limit();
753760
}
754761

762+
/*
763+
Returns true if we're currently running on the Rust stack
764+
*/
765+
bool
766+
rust_task::on_rust_stack() {
767+
return sp_in_stk_seg(get_sp(), stk);
768+
}
769+
755770
//
756771
// Local Variables:
757772
// mode: C++

src/rt/rust_task.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
202202
void del_stack();
203203
void record_stack_limit();
204204
void reset_stack_limit();
205+
bool on_rust_stack();
205206
};
206207

207208
//

src/rt/rust_upcall.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,8 @@ extern "C" CDECL void
8888
upcall_fail(char const *expr,
8989
char const *file,
9090
size_t line) {
91-
try {
92-
s_fail_args args = {expr,file,line};
93-
UPCALL_SWITCH_STACK(&args, upcall_s_fail);
94-
} catch (rust_task*) {
95-
throw;
96-
}
91+
s_fail_args args = {expr,file,line};
92+
UPCALL_SWITCH_STACK(&args, upcall_s_fail);
9793
}
9894

9995
/**********************************************************************
@@ -536,7 +532,18 @@ upcall_rust_personality(int version,
536532
s_rust_personality_args args = {(_Unwind_Reason_Code)0,
537533
version, actions, exception_class,
538534
ue_header, context};
539-
UPCALL_SWITCH_STACK(&args, upcall_s_rust_personality);
535+
rust_task *task = rust_scheduler::get_task();
536+
537+
// The personality function is run on the stack of the
538+
// last function that threw or landed, which is going
539+
// to sometimes be the C stack. If we're on the Rust stack
540+
// then switch to the C stack.
541+
542+
if (task->on_rust_stack()) {
543+
UPCALL_SWITCH_STACK(&args, upcall_s_rust_personality);
544+
} else {
545+
upcall_s_rust_personality(&args);
546+
}
540547
return args.retval;
541548
}
542549

0 commit comments

Comments
 (0)