about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-11-21 18:52:12 -0800
committerBrian Anderson <banderson@mozilla.com>2011-11-22 18:02:10 -0800
commit6bdf347418d04e48ef0fbbe0f4b2e940e9a24782 (patch)
tree9e3977e8dbf8d31415edba20a38904d7dfcf0247
parenta69c5617f02ff80dd7d39949004b386f9808b7d6 (diff)
downloadrust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.tar.gz
rust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.zip
rt: Make __morestack (without unwinding) work on 32-bit linux
-rw-r--r--mk/rt.mk3
-rw-r--r--src/rt/arch/i386/morestack.S44
-rw-r--r--src/rt/arch/i386/record_sp.S19
-rw-r--r--src/rt/rust_internal.h3
-rw-r--r--src/rt/rust_scheduler.cpp4
-rw-r--r--src/rt/rust_task.cpp32
-rw-r--r--src/rt/rust_task.h1
-rw-r--r--src/test/run-fail/morestack1.rs12
-rw-r--r--src/test/run-pass/morestack1.rs10
-rw-r--r--src/test/run-pass/morestack2.rs15
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