about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
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 /src/rt/rust_task.cpp
parenta69c5617f02ff80dd7d39949004b386f9808b7d6 (diff)
downloadrust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.tar.gz
rust-6bdf347418d04e48ef0fbbe0f4b2e940e9a24782.zip
rt: Make __morestack (without unwinding) work on 32-bit linux
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp32
1 files changed, 21 insertions, 11 deletions
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 *