From 68aff2ad6d55a051e9347aa38f945d114f282691 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 14 Nov 2011 13:52:35 -0800 Subject: [PATCH] rt: More work on morestack --- mk/rt.mk | 3 +- src/rt/arch/i386/morestack.S | 117 +++++++++++++++++++++++++++++------ src/rt/rust.cpp | 3 + src/rt/rust_scheduler.cpp | 10 +++ src/rt/rust_task.cpp | 29 +++++++-- src/rt/rustrt.def.in | 10 ++- 6 files changed, 143 insertions(+), 29 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index 0208fe7ab55..1d6634557d0 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -67,7 +67,8 @@ RUNTIME_CS_$(1) := \ RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \ rt/arch/$$(HOST_$(1))/ccall.S \ - rt/arch/$$(HOST_$(1))/morestack.S + rt/arch/$$(HOST_$(1))/morestack.S \ + rt/arch/$$(HOST_$(1))/record_sp.S RUNTIME_HDR_$(1) := rt/globals.h \ rt/rust.h \ diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S index 2f5987a4350..ec356ea91c6 100644 --- a/src/rt/arch/i386/morestack.S +++ b/src/rt/arch/i386/morestack.S @@ -2,40 +2,117 @@ // __morestack // -// LLVM generates a call to this to allocate more stack space in a functiono +// LLVM generates a call to this to allocate more stack space in a function // prolog when we run out. #if defined(__APPLE__) || defined(_WIN32) -#define RUST_NEW_STACK _rust_new_stack -#define RUST_DEL_STACK _rust_del_stack -#define MORESTACK ___morestack +#define RUST_NEW_STACK _rust_new_stack +#define RUST_DEL_STACK _rust_del_stack +#define RUST_GET_PREV_STACK _rust_get_prev_stack +#define RUST_GET_TASK _rust_get_task +#define UPCALL_ALLOC_C_STACK _upcall_alloc_c_stack +#define UPCALL_CALL_C_STACK _upcall_call_c_stack +#define MORESTACK ___morestack #else -#define RUST_NEW_STACK rust_new_stack -#define RUST_DEL_STACK rust_del_stack -#define MORESTACK __morestack +#define RUST_NEW_STACK rust_new_stack +#define RUST_DEL_STACK rust_del_stack +#define RUST_GET_PREV_STACK rust_get_prev_stack +#define RUST_GET_TASK rust_get_task +#define UPCALL_ALLOC_C_STACK upcall_alloc_c_stack +#define UPCALL_CALL_C_STACK upcall_call_c_stack +#define MORESTACK __morestack #endif +#ifdef __APPLE__ +#define ALIGNMENT 4 +#else +#define ALIGNMENT 8 +#endif + +#define RETURN_OFFSET 7 + .globl RUST_NEW_STACK .globl RUST_DEL_STACK - +.globl RUST_GET_PREV_STACK +.globl RUST_GET_TASK +.globl UPCALL_ALLOC_C_STACK +.globl UPCALL_CALL_C_STACK .globl MORESTACK MORESTACK: - pushl 8(%esp) // argsz > ra stksz argsz x x ra args - leal 28(%esp),%eax // argsz ra stksz argsz x x ra args - pushl %eax // argp > argsz ra stksz argsz x x ra args - pushl 12(%esp) // stksz > argp argsz ra stksz argsz x x ra args - calll RUST_NEW_STACK - addl $12,%esp // ra stksz argsz x x ra args - movl (%esp),%edx // Grab the return pointer. - incl %edx // Skip past the `ret`. - movl %eax,%esp // Switch to the new stack. + // Sanity check to make sure that there is a currently-running task. + subl $12,%esp + calll RUST_GET_TASK + testl %eax,%eax + jz L$bail + + subl $12,%esp + pushl $12 + calll UPCALL_ALLOC_C_STACK + movl %eax,%edx + + // C stack | esp+12 + // ---------------------+------------------------- + movl 20(%esp),%eax // | ra stksz argsz x ra args + movl %eax,8(%edx) // argsz > | ra stksz argsz x ra args + leal 32(%esp),%eax // argsz | ra stksz argsz x ra args + movl %eax,4(%edx) // argp > argsz | ra stksz argsz x ra args + movl 16(%esp),%eax // argp argsz | ra stksz argsz x ra args + movl %eax,(%edx) // stksz > argp argsz | ra stksz argsz x ra args + + calll L$pic_ref_pt_0 +L$pic_ref_pt_0: + popl %eax + + movl rust_new_stack_sym-L$pic_ref_pt_0(%eax),%eax + movl %eax,(%esp) + movl %edx,4(%esp) + calll UPCALL_CALL_C_STACK + + movl 16(%esp),%edx // Grab the return pointer. + addl $RETURN_OFFSET,%edx // Skip past the `add esp,4` and the `ret`. + + movl %eax,%esp // Switch stacks. + subl $12,%esp // Align the stack. calll *%edx // Re-enter the function that called us. // Now the function that called us has returned, so we need to delete the // old stack space. - calll RUST_DEL_STACK - movl %eax,%esp - retl $8 // ra stksz argsz x x ra args + + calll RUST_GET_PREV_STACK + movl %eax,%esp // Switch back to the old stack. + + movl $0,(%esp) + calll UPCALL_ALLOC_C_STACK + + calll L$pic_ref_pt_1 +L$pic_ref_pt_1: + popl %edx + + movl rust_del_stack_sym-L$pic_ref_pt_1(%edx),%edx + movl %edx,(%esp) + movl %eax,4(%esp) + calll UPCALL_CALL_C_STACK + + addl $16,%esp + retl $16 + ALIGNMENT // ra stksz argsz x ra args + +L$bail: + movl 12(%esp),%edx + addl $RETURN_OFFSET,%edx + addl $12+16,%esp + jmpl *%edx + +#ifdef __APPLE__ + + .section __IMPORT,__pointers,non_lazy_symbol_pointers +rust_new_stack_sym: + .indirect_symbol RUST_NEW_STACK + .long 0 +rust_del_stack_sym: + .indirect_symbol RUST_DEL_STACK + .long 0 + +#endif diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index b8a3cde5a93..0049537bd33 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -1,4 +1,5 @@ #include "rust_internal.h" +#include struct command_line_args : public kernel_owned @@ -75,6 +76,8 @@ int check_claims = 0; extern "C" CDECL int rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { + fprintf(stderr, "rust_start, argc=%d argv=%p\n", argc, argv); + rust_env *env = load_env(); update_log_settings(crate_map, env->logspec); diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 6a88c2f2417..b17565dda46 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -1,6 +1,7 @@ #include #include +#include #include "rust_internal.h" #include "globals.h" @@ -12,6 +13,9 @@ DWORD rust_scheduler::task_key; bool rust_scheduler::tls_initialized = false; +// Defined in arch/*/record_sp.S. +extern "C" void rust_record_sp(uintptr_t sp); + rust_scheduler::rust_scheduler(rust_kernel *kernel, rust_srv *srv, int id) : @@ -285,6 +289,8 @@ rust_scheduler::start_main_loop() { scheduled_task->state->name); place_task_in_tls(scheduled_task); + rust_record_sp(scheduled_task->stk->limit); + //pthread_setspecific(89, (void *)scheduled_task->stk->limit); interrupt_flag = 0; @@ -374,6 +380,8 @@ rust_scheduler::place_task_in_tls(rust_task *task) { rust_task * rust_scheduler::get_task() { + if (!tls_initialized) + return NULL; rust_task *task = reinterpret_cast (pthread_getspecific(task_key)); assert(task && "Couldn't get the task from TLS!"); @@ -395,6 +403,8 @@ rust_scheduler::place_task_in_tls(rust_task *task) { rust_task * rust_scheduler::get_task() { + if (!tls_initialized) + return NULL; rust_task *task = reinterpret_cast(TlsGetValue(task_key)); assert(task && "Couldn't get the task from TLS!"); return task; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 6d5241ff344..ae893c93fa0 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -8,11 +8,14 @@ #ifndef __WIN32__ #include #endif +#include #include #include #include "globals.h" +#define RED_ZONE_SIZE 128 + // Stack size size_t g_custom_min_stack_size = 0; @@ -34,16 +37,16 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) size_t min_stk_bytes = get_min_stk_size(sched->min_stack_size); if (minsz < min_stk_bytes) minsz = min_stk_bytes; - size_t sz = sizeof(stk_seg) + minsz; + size_t sz = sizeof(stk_seg) + minsz + RED_ZONE_SIZE; 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]; + stk->limit = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE]; LOGPTR(task->sched, "stk limit", stk->limit); stk->valgrind_id = VALGRIND_STACK_REGISTER(&stk->data[0], - &stk->data[minsz]); + &stk->data[minsz + RED_ZONE_SIZE]); task->stk = stk; return stk; } @@ -63,18 +66,32 @@ del_stk(rust_task *task, stk_seg *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) { + std::cerr << "*** New stack!\n"; + 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; } -extern "C" void * +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; +} + +extern "C" void * +rust_get_prev_stack() { + rust_task *task = rust_scheduler::get_task(); + return task->stk->next; +} + +extern "C" rust_task * +rust_get_task() { + return rust_scheduler::get_task(); } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index f5751b58bc0..bd051d01195 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -1,3 +1,4 @@ +__morestack align_of chan_id_send check_claims @@ -28,7 +29,10 @@ rand_free rand_new rand_next refcount +rust_del_stack rust_file_is_dir +rust_getcwd +rust_get_prev_stack rust_get_stdin rust_get_stdout rust_get_stderr @@ -36,12 +40,14 @@ rust_str_push rust_list_files rust_port_detach rust_port_size +rust_new_stack rust_process_wait rust_ptr_eq rust_run_program rust_start rust_getcwd rust_task_sleep +rust_get_task set_min_stack sched_threads size_of @@ -63,10 +69,10 @@ upcall_dynastack_mark upcall_fail upcall_free upcall_get_type_desc -upcall_vec_grow -upcall_vec_push upcall_log_type upcall_malloc upcall_rust_personality upcall_shared_malloc upcall_shared_free +upcall_vec_grow +upcall_vec_push