diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 419a7fdc34c..71f33ccb372 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -27,7 +27,8 @@ type upcalls = dynastack_free: ValueRef, alloc_c_stack: ValueRef, call_shim_on_c_stack: ValueRef, - rust_personality: ValueRef}; + rust_personality: ValueRef, + reset_stack_limit: ValueRef}; fn declare_upcalls(targ_cfg: @session::config, _tn: type_names, @@ -89,7 +90,8 @@ fn declare_upcalls(targ_cfg: @session::config, // arguments: void *args, void *fn_ptr [T_ptr(T_i8()), T_ptr(T_i8())], int_t), - rust_personality: d("rust_personality", [], T_i32()) + rust_personality: d("rust_personality", [], T_i32()), + reset_stack_limit: dv("reset_stack_limit", []) }; } // diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6804434bb4c..41df1b28edd 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3904,6 +3904,11 @@ fn trans_landing_pad(bcx: @block_ctxt, // The landing pad block is a cleanup SetCleanup(bcx, llpad); + // Because we may have unwound across a stack boundary, we must call into + // the runtime to figure out which stack segment we are on and place the + // stack limit back into the TLS. + Call(bcx, bcx_ccx(bcx).upcalls.reset_stack_limit, []); + // FIXME: This seems like a very naive and redundant way to generate the // landing pads, as we're re-generating all in-scope cleanups for each // function call. Probably good optimization opportunities here. diff --git a/src/rt/arch/i386/record_sp.S b/src/rt/arch/i386/record_sp.S index 153225e8187..3f299de5d15 100644 --- a/src/rt/arch/i386/record_sp.S +++ b/src/rt/arch/i386/record_sp.S @@ -2,11 +2,14 @@ #if defined(__APPLE__) || defined(_WIN32) #define RECORD_SP _record_sp +#define GET_SP _get_sp #else #define RECORD_SP record_sp +#define GET_SP get_sp #endif .globl RECORD_SP +.globl GET_SP #if defined(__linux__) RECORD_SP: @@ -25,3 +28,7 @@ RECORD_SP: ret #endif #endif + +GET_SP: + movl %esp, %eax + ret \ No newline at end of file diff --git a/src/rt/arch/x86_64/morestack.S b/src/rt/arch/x86_64/morestack.S index ef0edcee720..535b6190f1c 100644 --- a/src/rt/arch/x86_64/morestack.S +++ b/src/rt/arch/x86_64/morestack.S @@ -132,6 +132,10 @@ MORESTACK: addq $8, %rsp popq %rbp +#ifdef __linux__ + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 +#endif ret #if defined(__ELF__) diff --git a/src/rt/arch/x86_64/record_sp.S b/src/rt/arch/x86_64/record_sp.S index e8284c5fac9..415f6685655 100644 --- a/src/rt/arch/x86_64/record_sp.S +++ b/src/rt/arch/x86_64/record_sp.S @@ -2,11 +2,14 @@ #if defined(__APPLE__) || defined(_WIN32) #define RECORD_SP _record_sp +#define GET_SP _get_sp #else #define RECORD_SP record_sp +#define GET_SP get_sp #endif .globl RECORD_SP +.globl GET_SP #if defined(__linux__) RECORD_SP: @@ -23,3 +26,7 @@ RECORD_SP: ret #endif #endif + +GET_SP: + movq %rsp, %rax + ret diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index b540225243f..888c9ac701a 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -18,11 +18,11 @@ // to the rt, compiler and dynamic linker for running small functions // FIXME: We want this to be 128 but need to slim the red zone calls down #ifdef __i386__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif #ifdef __x86_64__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif // Stack size @@ -613,6 +613,29 @@ rust_task::record_stack_limit() { "Stack size must be greater than LIMIT_OFFSET"); record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); } + +extern "C" uintptr_t get_sp(); + +/* +Called by landing pads during unwinding to figure out which +stack segment we are currently running on, delete the others, +and record the stack limit (which was not restored when unwinding +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->limit, which points one word in front of + // the first work to be pushed onto a new stack. + while (sp <= (uintptr_t)stk->data || stk->limit < sp) { + del_stk(this, stk); + A(sched, stk != NULL, "Failed to find the current stack"); + } + record_stack_limit(); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 00a9fc277dc..47472801510 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -200,6 +200,7 @@ rust_task : public kernel_owned, rust_cond void *new_stack(size_t stk_sz, void *args_addr, size_t args_sz); void del_stack(); void record_stack_limit(); + void reset_stack_limit(); }; // diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 653db471fc0..5a4c37c500c 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -259,6 +259,15 @@ upcall_del_stack() { task->del_stack(); } +// Landing pads need to call this to insert the +// correct limit into TLS. +// NB: This must be called on the Rust stack +extern "C" CDECL void +upcall_reset_stack_limit() { + rust_task *task = rust_scheduler::get_task(); + task->reset_stack_limit(); +} + extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index ba1a9c1403d..306c750c8fb 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -69,6 +69,7 @@ upcall_vec_push upcall_call_shim_on_c_stack upcall_new_stack upcall_del_stack +upcall_reset_stack_limit asm_call_on_stack rust_uv_default_loop rust_uv_loop_new diff --git a/src/test/run-fail/morestack3.rs b/src/test/run-fail/morestack3.rs index 9fdd0326b66..9796017a8eb 100644 --- a/src/test/run-fail/morestack3.rs +++ b/src/test/run-fail/morestack3.rs @@ -25,10 +25,10 @@ resource and_then_get_big_again(_i: @int) { getbig(i - 1); } } - getbig(1000); + getbig(100); } fn main() { rustrt::set_min_stack(256u); - std::task::spawn(1000, getbig_and_fail); + std::task::spawn(100, getbig_and_fail); } \ No newline at end of file