From 50954b670ac3eaa05a61b0e07cc3426f5f9119fd Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 16 Aug 2017 22:14:39 -0700 Subject: Get continuations working on aarch64. * unwind.c (UW_CONT_FRAME_BEFORE, UW_CONT_FRAME_AFTER): New preprocessor symbols. (revive_cont): The "frame slack" zero-filled padding logic is replaced by capturing an actual part of the real stack before the uw_stack unwind frame. On aarch64, there is content there we must actually capture. Experiment shows that exactly 128 bytes is enough, and that corresponds to the frame_slack value. (capture_cont): Capture UW_CONT_FRAME_BEFORE bytes before the uw_stack unwind frame location. Also, the "capture_extra" is replaced by UW_CONT_FRAME_AFTER constant, to harmonize. * unwind.h (UW_FRAME_ALIGN): New preprocessor symbol. (union uw_frame): On aarch64, we ask the compiler, via a GCC-specific attribute syntax, to align the address of frame objects to a 16 byte boundary. This solves a crash in the continuation code. Continuation capture is keyed to unwind frame addresses. When a captured continuation is revived onto the stack, the delta between its original address and the revive address must be a multiple of 16. The reason is that this preserves the stack and frame pointer alignment. Certain instructions on the aarch64, require the stack pointer to be 16 byte aligned. There are other ways we could achieve this, but the easiest is to align the original frames to 16 bytes. --- unwind.c | 29 +++++++++++++++-------------- unwind.h | 8 +++++++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/unwind.c b/unwind.c index 94763e7e..e4cc28f3 100644 --- a/unwind.c +++ b/unwind.c @@ -49,6 +49,9 @@ #include ALLOCA_H #include "unwind.h" +#define UW_CONT_FRAME_BEFORE (32 * sizeof (val)) +#define UW_CONT_FRAME_AFTER (16 * sizeof (val)) + static uw_frame_t *uw_stack; static uw_frame_t *uw_env_stack; static uw_frame_t *uw_exit_point; @@ -862,7 +865,6 @@ static void call_copy_handlers(uw_frame_t *upto, int parent) static val revive_cont(val dc, val arg) { - const int frame_slack = 32 * sizeof (val); struct cont *cont = coerce(struct cont *, cobj_handle(dc, sys_cont_s)); if (arg == sys_cont_free_s) { @@ -870,15 +872,14 @@ static val revive_cont(val dc, val arg) cont->stack = 0; return nil; } else if (cont->stack) { - mem_t *space = coerce(mem_t *, alloca(cont->size + frame_slack)) + frame_slack; + mem_t *space = coerce(mem_t *, alloca(cont->size)); uint_ptr_t orig_start = coerce(uint_ptr_t, cont->orig); uint_ptr_t orig_end = orig_start + cont->size; cnum delta = space - coerce(mem_t *, cont->orig); mem_t *ptr; - uw_frame_t *new_uw_stack = coerce(uw_frame_t *, space), *fr; + uw_frame_t *new_uw_stack = coerce(uw_frame_t *, space + UW_CONT_FRAME_BEFORE), *fr; int env_set = 0; - memset(space - frame_slack, 0, frame_slack); memcpy(space, cont->stack, cont->size); for (ptr = space; ptr < space + cont->size; ptr += sizeof (cnum)) @@ -895,7 +896,7 @@ static val revive_cont(val dc, val arg) #endif word = *wordptr; - if (word >= orig_start - frame_slack && + if (word >= orig_start - UW_CONT_FRAME_BEFORE && word < orig_end && is_ptr(coerce(val, word))) *wordptr = word + delta; @@ -944,24 +945,24 @@ static val capture_cont(val tag, val fun, uw_frame_t *block) { volatile val cont_obj = nil; uw_block_begin (nil, result); + mem_t *stack = coerce(mem_t *, uw_stack) - UW_CONT_FRAME_BEFORE; bug_unless (uw_stack < block); { - const int capture_extra = 16 * sizeof (val); - mem_t *lim = coerce(mem_t *, block + 1) + capture_extra; - cnum bloff = coerce(mem_t *, block) - coerce(mem_t *, uw_stack); - cnum size = coerce(mem_t *, lim) - coerce(mem_t *, uw_stack); - mem_t *stack = chk_malloc(size); - uw_frame_t *blcopy = coerce(uw_frame_t *, stack + bloff); + mem_t *lim = coerce(mem_t *, block + 1) + UW_CONT_FRAME_AFTER; + cnum bloff = coerce(mem_t *, block) - coerce(mem_t *, stack); + cnum size = coerce(mem_t *, lim) - coerce(mem_t *, stack); + mem_t *stack_copy = chk_malloc(size); + uw_frame_t *blcopy = coerce(uw_frame_t *, stack_copy + bloff); struct cont *cont = coerce(struct cont *, chk_malloc(sizeof *cont)); - cont->orig = uw_stack; + cont->orig = coerce(uw_frame_t *, stack); cont->size = size; - cont->stack = stack; + cont->stack = stack_copy; cont->tag = nil; - memcpy(stack, uw_stack, size); + memcpy(stack_copy, stack, size); blcopy->uw.up = 0; blcopy->uw.type = UW_CAPTURED_BLOCK; diff --git a/unwind.h b/unwind.h index c887a423..a173e39d 100644 --- a/unwind.h +++ b/unwind.h @@ -98,6 +98,12 @@ struct uw_debug { val chr; }; +#if __aarch64__ +#define UW_FRAME_ALIGN __attribute__ ((aligned (16))) +#else +#define UW_FRAME_ALIGN +#endif + union uw_frame { struct uw_common uw; struct uw_block bl; @@ -107,7 +113,7 @@ union uw_frame { struct uw_cont_copy cp; struct uw_guard gu; struct uw_debug db; -}; +} UW_FRAME_ALIGN; void uw_push_block(uw_frame_t *, val tag); void uw_push_env(uw_frame_t *); -- cgit v1.2.3