summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-08-16 22:14:39 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-08-16 22:14:39 -0700
commit2399bf36c10ec9f7011008a76f96847be7255c9d (patch)
treec6b08adb149a32adf43e5f8062ca358f046bfd4d
parente31b1509ebb518548780aa2544459337854af48e (diff)
downloadtxr-2399bf36c10ec9f7011008a76f96847be7255c9d.tar.gz
txr-2399bf36c10ec9f7011008a76f96847be7255c9d.tar.bz2
txr-2399bf36c10ec9f7011008a76f96847be7255c9d.zip
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.
-rw-r--r--unwind.c29
-rw-r--r--unwind.h8
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 *);