]> git.lizzy.rs Git - rust.git/commitdiff
rt: Get rid of the rethrow in upcall_fail
authorBrian Anderson <banderson@mozilla.com>
Mon, 19 Dec 2011 00:59:49 +0000 (16:59 -0800)
committerBrian Anderson <banderson@mozilla.com>
Mon, 19 Dec 2011 01:17:31 +0000 (17:17 -0800)
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
src/rt/rust_task.h
src/rt/rust_upcall.cpp

index f74f821819c01f366c7aa391708c112c596a2a80..f30315174b6f19a27b6bbf506945a60a69b0cb18 100644 (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++
index 3339ad42bfdd268f6e61eaab84ce337af1bc8808..51ae00a6b7077e06b1eaa52e6d84bc9802539ede 100644 (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();
 };
 
 //
index 506441979cacfef545e77a78e8af50d8868ddd12..5febc5098a21e7ea640e28b6acf607b51c9c80c1 100644 (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;
 }