From 1eaaae860fb725f5afdd8912fb2200f4f9929daa Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 28 Sep 2011 11:31:44 -0700 Subject: [PATCH] rt: Add an upcall to allocate space on the C stack. This will be used for native calls on the C stack. --- src/rt/arch/i386/context.h | 27 ++++++++++++++++++--------- src/rt/intrinsics/intrinsics.cpp | 2 ++ src/rt/rust_upcall.cpp | 10 ++++++++++ src/rt/rustrt.def.in | 1 + 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/rt/arch/i386/context.h b/src/rt/arch/i386/context.h index 457eaf396702..a31b4c48d145 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 #include +#include + +template +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); + + // 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)); + } }; -template -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)); -} - #endif diff --git a/src/rt/intrinsics/intrinsics.cpp b/src/rt/intrinsics/intrinsics.cpp index bbe0fc811dd3..2cd4198e3a07 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 #include @@ -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 60802be4ac05..e196adf70f0a 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 bf8155b7998a..f5f75d61c94b 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