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