about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-09-28 11:31:44 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-09-28 11:31:44 -0700
commit1eaaae860fb725f5afdd8912fb2200f4f9929daa (patch)
tree2e92a5f6a4ec86fe349b9e5db748f64ec3e68870
parente8757ea01f39826911a4c05ddf4b7e6990a56f27 (diff)
downloadrust-1eaaae860fb725f5afdd8912fb2200f4f9929daa.tar.gz
rust-1eaaae860fb725f5afdd8912fb2200f4f9929daa.zip
rt: Add an upcall to allocate space on the C stack. This will be used for native calls on the C stack.
-rw-r--r--src/rt/arch/i386/context.h27
-rw-r--r--src/rt/intrinsics/intrinsics.cpp2
-rw-r--r--src/rt/rust_upcall.cpp10
-rw-r--r--src/rt/rustrt.def.in1
4 files changed, 31 insertions, 9 deletions
diff --git a/src/rt/arch/i386/context.h b/src/rt/arch/i386/context.h
index 457eaf39670..a31b4c48d14 100644
--- a/src/rt/arch/i386/context.h
+++ b/src/rt/arch/i386/context.h
@@ -3,7 +3,17 @@
 #ifndef CONTEXT_H
 #define CONTEXT_H
 
+#include <cstdlib>
 #include <inttypes.h>
+#include <stdint.h>
+
+template<typename T>
+T align_down(T sp)
+{
+    // There is no platform we care about that needs more than a
+    // 16-byte alignment.
+    return (T)((uint32_t)sp & ~(16 - 1));
+}
 
 struct registers_t {
   // general purpose registers
@@ -26,16 +36,15 @@ public:
   context *next;
 
   void swap(context &out);
-
   void call(void *f, void *arg, void *sp);
-};
 
-template<typename T>
-T align_down(T sp)
-{
-    // There is no platform we care about that needs more than a
-    // 16-byte alignment.
-    return (T)((int)sp & ~(16 - 1));
-}
+  // Note that this doesn't actually adjust esp. Instead, we adjust esp when
+  // we actually do the call. This is needed for exception safety -- if the
+  // function being called causes the task to fail, then we have to avoid
+  // leaking space on the C stack.
+  inline void *alloc_stack(size_t nbytes) {
+    return (void *)(align_down(regs.esp - nbytes));
+  }
+};
 
 #endif
diff --git a/src/rt/intrinsics/intrinsics.cpp b/src/rt/intrinsics/intrinsics.cpp
index bbe0fc811dd..2cd4198e3a0 100644
--- a/src/rt/intrinsics/intrinsics.cpp
+++ b/src/rt/intrinsics/intrinsics.cpp
@@ -2,6 +2,7 @@
 //      -I../arch/i386 -fno-stack-protector -o intrinsics.ll intrinsics.cpp`
 
 #include "../rust_internal.h"
+#include "../rust_scheduler.h"
 #include <cstdlib>
 #include <cstring>
 
@@ -46,3 +47,4 @@ rust_intrinsic_recv(rust_task *task, void **retptr, type_desc *ty,
                     rust_port *port) {
     port_recv(task, (uintptr_t*)retptr, port);
 }
+
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 60802be4ac0..e196adf70f0 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -202,6 +202,16 @@ upcall_dynastack_free(rust_task *task, void *ptr) {
     return task->dynastack.free(ptr);
 }
 
+/**
+ * Allocates |nbytes| bytes in the C stack and returns a pointer to the start
+ * of the allocated space.
+ */
+extern "C" CDECL void *
+upcall_alloc_c_stack(size_t nbytes) {
+    rust_scheduler *sched = rust_scheduler::get_task()->sched;
+    return sched->c_context.alloc_stack(nbytes);
+}
+
 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 bf8155b7998..f5f75d61c94 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -65,6 +65,7 @@ task_sleep
 task_yield
 task_join
 unsupervise
+upcall_alloc_c_stack
 upcall_cmp_type
 upcall_dynastack_alloc
 upcall_dynastack_alloc_2