about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-10-31 13:31:04 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-10-31 14:20:56 -0700
commitc9003d301f602cb44d8cc3fd464c95b09e08548e (patch)
tree26b07c6d9da42436b7c2cfebbf08ad7404bb059e
parent799ba7b1226cda3cf167cbe1c7e8aaf2f78c82f9 (diff)
downloadrust-c9003d301f602cb44d8cc3fd464c95b09e08548e.tar.gz
rust-c9003d301f602cb44d8cc3fd464c95b09e08548e.zip
Stub a __morestack implementation and stack segment allocation. Untested.
-rw-r--r--mk/rt.mk3
-rw-r--r--mk/rustllvm.mk5
-rw-r--r--src/rt/arch/i386/morestack.S38
-rw-r--r--src/rt/rust_task.cpp26
-rw-r--r--src/rt/rust_task.h7
5 files changed, 77 insertions, 2 deletions
diff --git a/mk/rt.mk b/mk/rt.mk
index 07d1879efc2..8d096558923 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -38,7 +38,8 @@ RUNTIME_CS := rt/sync/timer.cpp \
 RUNTIME_LL :=
 
 RUNTIME_S := rt/arch/i386/_context.S \
-             rt/arch/i386/ccall.S
+             rt/arch/i386/ccall.S \
+             rt/arch/i386/morestack.S
 
 RUNTIME_HDR := rt/globals.h \
                rt/rust.h \
diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk
index d8f9dd2ce52..7df9e3366e0 100644
--- a/mk/rustllvm.mk
+++ b/mk/rustllvm.mk
@@ -5,6 +5,11 @@
 RUSTLLVM_OBJS_CS := $(addprefix rustllvm/, RustGCMetadataPrinter.cpp \
     RustGCStrategy.cpp RustWrapper.cpp)
 
+# Behind an ifdef for now since this requires a patched LLVM.
+ifdef CFG_STACK_GROWTH
+RUSTLLVM_OBJS_CS += rustllvm/RustPrologHook.cpp
+endif
+
 RUSTLLVM_DEF := rustllvm/rustllvm$(CFG_DEF_SUFFIX)
 
 RUSTLLVM_INCS := -iquote $(CFG_LLVM_INCDIR) \
diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S
new file mode 100644
index 00000000000..23492637fdb
--- /dev/null
+++ b/src/rt/arch/i386/morestack.S
@@ -0,0 +1,38 @@
+    .text
+
+// __morestack
+//
+// LLVM generates a call to this to allocate more stack space in a functiono
+// prolog when we run out.
+
+#if defined(__APPLE__) || defined(_WIN32)
+#define RUST_NEW_STACK      _rust_new_stack
+#define RUST_DEL_STACK      _rust_del_stack
+#else
+#define RUST_NEW_STACK      rust_new_stack
+#define RUST_DEL_STACK      rust_del_stack
+#endif
+
+.globl RUST_NEW_STACK
+.globl RUST_DEL_STACK
+
+.globl __morestack
+
+__morestack:
+    pushl %edx              // param 2: size of arguments
+    leal 8(%esp),%eax
+    pushl %eax              // param 1: starting addr of arguments
+    pushl %ecx              // param 0: amount of space needed
+    calll RUST_NEW_STACK
+
+    movl (%esp),%edx        // Grab the return pointer.
+    incl %edx               // Skip past the `ret`.
+    movl %eax,%esp          // Switch to the new stack.
+    calll *%edx             // Enter the new function.
+
+    // Now the function that called us has returned, so we need to delete the
+    // old stack space.
+    calll RUST_DEL_STACK
+    movl %eax,%esp          // Switch back to the old stack.
+    retl
+
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 17faeec1a1c..5043f9ec4b0 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -8,6 +8,8 @@
 #ifndef __WIN32__
 #include <execinfo.h>
 #endif
+#include <cassert>
+#include <cstring>
 
 #include "globals.h"
 
@@ -36,22 +38,46 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz)
     stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
     LOGPTR(task->sched, "new stk", (uintptr_t)stk);
     memset(stk, 0, sizeof(stk_seg));
+    stk->next = task->stk;
     stk->limit = (uintptr_t) &stk->data[minsz];
     LOGPTR(task->sched, "stk limit", stk->limit);
     stk->valgrind_id =
         VALGRIND_STACK_REGISTER(&stk->data[0],
                                 &stk->data[minsz]);
+    task->stk = stk;
     return stk;
 }
 
 static void
 del_stk(rust_task *task, stk_seg *stk)
 {
+    assert(stk == task->stk && "Freeing stack segments out of order!");
+
+    task->stk = stk->next;
+
     VALGRIND_STACK_DEREGISTER(stk->valgrind_id);
     LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
     task->free(stk);
 }
 
+// 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) {
+    rust_task *task = rust_scheduler::get_task();
+    stk_seg *stk_seg = new_stk(task->sched, task, stk_sz);
+    memcpy(stk_seg->data, args_addr, args_sz);
+    return stk_seg->data;
+}
+
+extern "C" void *
+rust_del_stack() {
+    rust_task *task = rust_scheduler::get_task();
+    stk_seg *next_seg = task->stk->next;
+    del_stk(task, task->stk);
+    return next_seg->data;
+}
+
+
 // Tasks
 rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
                      rust_task *spawner, const char *name) :
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index fe19e06e657..783d46eaced 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -24,8 +24,13 @@ struct chan_handle {
 struct rust_box;
 
 struct stk_seg {
-    unsigned int valgrind_id;
+    stk_seg *next;
     uintptr_t limit;
+    unsigned int valgrind_id;
+#ifndef _LP64
+    uint32_t pad;
+#endif
+
     uint8_t data[];
 };