diff options
| author | Brian Anderson <banderson@mozilla.com> | 2011-11-21 18:52:12 -0800 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2011-11-22 18:02:10 -0800 |
| commit | 6bdf347418d04e48ef0fbbe0f4b2e940e9a24782 (patch) | |
| tree | 9e3977e8dbf8d31415edba20a38904d7dfcf0247 | |
| parent | a69c5617f02ff80dd7d39949004b386f9808b7d6 (diff) | |
| download | rust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.tar.gz rust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.zip | |
rt: Make __morestack (without unwinding) work on 32-bit linux
| -rw-r--r-- | mk/rt.mk | 3 | ||||
| -rw-r--r-- | src/rt/arch/i386/morestack.S | 44 | ||||
| -rw-r--r-- | src/rt/arch/i386/record_sp.S | 19 | ||||
| -rw-r--r-- | src/rt/rust_internal.h | 3 | ||||
| -rw-r--r-- | src/rt/rust_scheduler.cpp | 4 | ||||
| -rw-r--r-- | src/rt/rust_task.cpp | 32 | ||||
| -rw-r--r-- | src/rt/rust_task.h | 1 | ||||
| -rw-r--r-- | src/test/run-fail/morestack1.rs | 12 | ||||
| -rw-r--r-- | src/test/run-pass/morestack1.rs | 10 | ||||
| -rw-r--r-- | src/test/run-pass/morestack2.rs | 15 |
10 files changed, 112 insertions, 31 deletions
diff --git a/mk/rt.mk b/mk/rt.mk index 0208fe7ab55..1d6634557d0 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -67,7 +67,8 @@ RUNTIME_CS_$(1) := \ RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \ rt/arch/$$(HOST_$(1))/ccall.S \ - rt/arch/$$(HOST_$(1))/morestack.S + rt/arch/$$(HOST_$(1))/morestack.S \ + rt/arch/$$(HOST_$(1))/record_sp.S RUNTIME_HDR_$(1) := rt/globals.h \ rt/rust.h \ diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S index b8e14bdb579..d3e9d81248d 100644 --- a/src/rt/arch/i386/morestack.S +++ b/src/rt/arch/i386/morestack.S @@ -29,6 +29,14 @@ #define ALIGNMENT 8 #endif +#if defined (__APPLE__) || defined(_WIN32) +#define NEW_STACK_ADDR rust_new_stack_sym-.L$pic_ref_pt_0(%eax) +#define DEL_STACK_ADDR rust_del_stack_sym-.L$pic_ref_pt_1(%edx) +#else +#define NEW_STACK_ADDR $rust_new_stack +#define DEL_STACK_ADDR $rust_del_stack +#endif + #define RETURN_OFFSET 7 .globl RUST_NEW_STACK @@ -39,6 +47,10 @@ .globl UPCALL_CALL_C_STACK .globl MORESTACK +#ifdef __ELF__ + .type MORESTACK,@function +#endif + MORESTACK: // Sanity check to make sure that there is a currently-running task. @@ -47,34 +59,33 @@ MORESTACK: testl %eax,%eax jz L$bail - subl $12,%esp - pushl $12 + movl $12, (%esp) calll UPCALL_ALLOC_C_STACK movl %eax,%edx + movl %esp, 12(%edx) // C stack | esp+12 // ---------------------+------------------------- movl 20(%esp),%eax // | ra stksz argsz x ra args movl %eax,8(%edx) // argsz > | ra stksz argsz x ra args - leal 32(%esp),%eax // argsz | ra stksz argsz x ra args + leal 28+ALIGNMENT(%esp),%eax // argsz | ra stksz argsz x ra args movl %eax,4(%edx) // argp > argsz | ra stksz argsz x ra args movl 16(%esp),%eax // argp argsz | ra stksz argsz x ra args movl %eax,(%edx) // stksz > argp argsz | ra stksz argsz x ra args - calll L$pic_ref_pt_0 -L$pic_ref_pt_0: + calll .L$pic_ref_pt_0 +.L$pic_ref_pt_0: popl %eax - movl rust_new_stack_sym-L$pic_ref_pt_0(%eax),%eax + movl NEW_STACK_ADDR,%eax movl %eax,(%esp) movl %edx,4(%esp) calll UPCALL_CALL_C_STACK - movl 16(%esp),%edx // Grab the return pointer. + movl 12(%esp),%edx // Grab the return pointer. addl $RETURN_OFFSET,%edx // Skip past the `add esp,4` and the `ret`. movl %eax,%esp // Switch stacks. - subl $12,%esp // Align the stack. calll *%edx // Re-enter the function that called us. // Now the function that called us has returned, so we need to delete the @@ -86,22 +97,22 @@ L$pic_ref_pt_0: movl $0,(%esp) calll UPCALL_ALLOC_C_STACK - calll L$pic_ref_pt_1 -L$pic_ref_pt_1: + calll .L$pic_ref_pt_1 +.L$pic_ref_pt_1: popl %edx - movl rust_del_stack_sym-L$pic_ref_pt_1(%edx),%edx + movl DEL_STACK_ADDR,%edx movl %edx,(%esp) movl %eax,4(%esp) calll UPCALL_CALL_C_STACK - addl $16,%esp - retl $16 + ALIGNMENT // ra stksz argsz x ra args + addl $12,%esp + retl $8 // ra stksz argsz x ra args L$bail: movl 12(%esp),%edx addl $RETURN_OFFSET,%edx - addl $12+16,%esp + addl $12+4+8+ALIGNMENT,%esp jmpl *%edx #ifdef __APPLE__ @@ -114,10 +125,5 @@ rust_del_stack_sym: .indirect_symbol RUST_DEL_STACK .long 0 -#else - -rust_new_stack_sym: -rust_del_stack_sym: - #endif diff --git a/src/rt/arch/i386/record_sp.S b/src/rt/arch/i386/record_sp.S new file mode 100644 index 00000000000..78c77b9859d --- /dev/null +++ b/src/rt/arch/i386/record_sp.S @@ -0,0 +1,19 @@ +.text + +#if defined(__APPLE__) || defined(_WIN32) +#define RECORD_SP _record_sp +#else +#define RECORD_SP record_sp +#endif + +.globl RECORD_SP + +#if defined(__linux__) +RECORD_SP: + movl 4(%esp), %eax + movl %eax, %gs:48 + ret +#else +RECORD_SP: + ret +#endif \ No newline at end of file diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index 1e65d701e8f..734b4de79ad 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -94,6 +94,9 @@ static size_t const BUF_BYTES = 2048; // The error status to use when the process fails #define PROC_FAIL_CODE 101; +// FIXME: We want this to be 128 but need to slim the red zone calls down +#define RED_ZONE_SIZE 256 + // Every reference counted object should use this macro and initialize // ref_count. diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 26ceb3bccb3..d12f37107a4 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -367,10 +367,14 @@ rust_scheduler::init_tls() { tls_initialized = true; } +extern "C" CDECL void +record_sp(void *limit); + void rust_scheduler::place_task_in_tls(rust_task *task) { int result = pthread_setspecific(task_key, task); assert(!result && "Couldn't place the task in TLS!"); + record_sp(task->stk->data + RED_ZONE_SIZE); } rust_task * diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index fbaaebb8289..30489b1d669 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -14,7 +14,6 @@ #include "globals.h" -#define RED_ZONE_SIZE 128 // Stack size size_t g_custom_min_stack_size = 0; @@ -63,30 +62,41 @@ del_stk(rust_task *task, stk_seg *stk) task->free(stk); } +extern "C" CDECL void +record_sp(void *limit); + // Entry points for `__morestack` (see arch/*/morestack.S). extern "C" void * -rust_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) { - std::cerr << "*** New stack!\n"; - +rust_new_stack(size_t stk_sz, void *args_addr, size_t args_sz, + uintptr_t current_sp) { rust_task *task = rust_scheduler::get_task(); - if (!task) - return NULL; - stk_seg *stk_seg = new_stk(task->sched, task, stk_sz); - memcpy(stk_seg->data, args_addr, args_sz); - return stk_seg->data; + stk_seg *stk_seg = new_stk(task->sched, task, stk_sz + args_sz); + + // Save the previous stack pointer so it can be restored later + stk_seg->return_sp = current_sp; + uint8_t *new_sp = (uint8_t*)stk_seg->limit; + size_t sizeof_retaddr = sizeof(void*); + // Make enough room on the new stack to hold the old stack pointer + // in addition to the function arguments + new_sp = align_down(new_sp - (args_sz + sizeof_retaddr)); + new_sp += sizeof_retaddr; + memcpy(new_sp, args_addr, args_sz); + record_sp(stk_seg->data + RED_ZONE_SIZE); + return new_sp; } extern "C" void rust_del_stack() { rust_task *task = rust_scheduler::get_task(); del_stk(task, task->stk); + record_sp(task->stk->data + RED_ZONE_SIZE); } -extern "C" void * +extern "C" uintptr_t rust_get_prev_stack() { rust_task *task = rust_scheduler::get_task(); - return task->stk->next; + return task->stk->return_sp; } extern "C" rust_task * diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index a6d68331fda..bda51937ce1 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -26,6 +26,7 @@ struct rust_box; struct stk_seg { stk_seg *next; uintptr_t limit; + uintptr_t return_sp; unsigned int valgrind_id; #ifndef _LP64 uint32_t pad; diff --git a/src/test/run-fail/morestack1.rs b/src/test/run-fail/morestack1.rs new file mode 100644 index 00000000000..e3165fb9c0d --- /dev/null +++ b/src/test/run-fail/morestack1.rs @@ -0,0 +1,12 @@ +// xfail-test +fn getbig(i: int) { + if i != 0 { + getbig(i - 1); + } else { + fail; + } +} + +fn main() { + getbig(10000000); +} \ No newline at end of file diff --git a/src/test/run-pass/morestack1.rs b/src/test/run-pass/morestack1.rs new file mode 100644 index 00000000000..f37debc3281 --- /dev/null +++ b/src/test/run-pass/morestack1.rs @@ -0,0 +1,10 @@ +// xfail-test +fn getbig(i: int) { + if i != 0 { + getbig(i - 1); + } +} + +fn main() { + getbig(10000000); +} \ No newline at end of file diff --git a/src/test/run-pass/morestack2.rs b/src/test/run-pass/morestack2.rs new file mode 100644 index 00000000000..2f9cca7c7d9 --- /dev/null +++ b/src/test/run-pass/morestack2.rs @@ -0,0 +1,15 @@ +// xfail-test +fn getbig(i: int) -> int { + let m = if i >= 0 { + let j = getbig(i - 1); + let k = getbig(j - 1); + k + } else { + 0 + }; + m +} + +fn main() { + getbig(10000000); +} \ No newline at end of file |
