From ab83cbb90b280195e636976098d3674f5ffc1d0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 29 Oct 2014 14:38:42 -0400 Subject: [PATCH] arm: Add support for Go closures --- src/arm/ffi.c | 78 +++++++++++++++++++++++++++++++++++++-------- src/arm/ffitarget.h | 1 + src/arm/sysv.S | 63 +++++++++++++++++++++++------------- 3 files changed, 106 insertions(+), 36 deletions(-) diff --git a/src/arm/ffi.c b/src/arm/ffi.c index eabab47f..9c8732d1 100644 --- a/src/arm/ffi.c +++ b/src/arm/ffi.c @@ -308,6 +308,7 @@ struct call_frame void *lr; void *rvalue; int flags; + void *closure; }; extern void ffi_call_SYSV (void *stack, struct call_frame *, @@ -315,8 +316,9 @@ extern void ffi_call_SYSV (void *stack, struct call_frame *, extern void ffi_call_VFP (void *vfp_space, struct call_frame *, void (*fn) (void), unsigned vfp_used) FFI_HIDDEN; -void -ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) +static void +ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) { int flags = cif->flags; ffi_type *rtype = cif->rtype; @@ -364,6 +366,7 @@ ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) frame->rvalue = new_rvalue; frame->flags = flags; + frame->closure = closure; if (vfp_space) { @@ -380,6 +383,19 @@ ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) memcpy (rvalue, new_rvalue, rtype->size); } +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} + static void * ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue, char *argp, void **avalue) @@ -476,31 +492,43 @@ ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack, return rvalue; } -int FFI_HIDDEN -ffi_closure_inner_SYSV (ffi_closure *closure, void *rvalue, char *argp) +struct closure_frame { - ffi_cif *cif = closure->cif; - void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); + char vfp_space[8*8] __attribute__((aligned(8))); + char result[8*4]; + char argp[]; +}; - rvalue = ffi_prep_incoming_args_SYSV (cif, rvalue, argp, avalue); - closure->fun (cif, rvalue, avalue, closure->user_data); +int FFI_HIDDEN +ffi_closure_inner_SYSV (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + struct closure_frame *frame) +{ + void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); + void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result, + frame->argp, avalue); + fun (cif, rvalue, avalue, user_data); return cif->flags; } int FFI_HIDDEN -ffi_closure_inner_VFP (ffi_closure *closure, void *rvalue, - char *argp, char *vfp_space) +ffi_closure_inner_VFP (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + struct closure_frame *frame) { - ffi_cif *cif = closure->cif; void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); - - rvalue = ffi_prep_incoming_args_VFP (cif, rvalue, argp, vfp_space, avalue); - closure->fun (cif, rvalue, avalue, closure->user_data); + void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp, + frame->vfp_space, avalue); + fun (cif, rvalue, avalue, user_data); return cif->flags; } void ffi_closure_SYSV (void) FFI_HIDDEN; void ffi_closure_VFP (void) FFI_HIDDEN; +void ffi_go_closure_SYSV (void) FFI_HIDDEN; +void ffi_go_closure_VFP (void) FFI_HIDDEN; #if FFI_EXEC_TRAMPOLINE_TABLE @@ -785,6 +813,28 @@ ffi_prep_closure_loc (ffi_closure * closure, return FFI_OK; } +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ + void (*closure_func) (void) = ffi_go_closure_SYSV; + + if (cif->abi == FFI_VFP) + { + /* We only need take the vfp path if there are vfp arguments. */ + if (cif->vfp_used) + closure_func = ffi_go_closure_VFP; + } + else if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + closure->tramp = closure_func; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + /* Below are routines for VFP hard-float support. */ /* A subroutine of vfp_type_p. Given a structure type, return the type code diff --git a/src/arm/ffitarget.h b/src/arm/ffitarget.h index 744a1e19..4f473f92 100644 --- a/src/arm/ffitarget.h +++ b/src/arm/ffitarget.h @@ -62,6 +62,7 @@ typedef enum ffi_abi { /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 12 #define FFI_NATIVE_RAW_API 0 diff --git a/src/arm/sysv.S b/src/arm/sysv.S index ce5450dc..fd165890 100644 --- a/src/arm/sysv.S +++ b/src/arm/sysv.S @@ -136,6 +136,7 @@ ARM_FUNC_START(ffi_call_SYSV, 1) mov sp, r0 @ install the stack pointer mov lr, r2 @ move the fn pointer out of the way + ldr ip, [fp, #16] @ install the static chain ldmia sp!, {r0-r3} @ move first 4 parameters in registers. blx lr @ call fn @@ -180,22 +181,33 @@ ARM_FUNC_END(ffi_call_SYSV) /* - unsigned int FFI_HIDDEN - ffi_closure_inner (closure, respp, args) - ffi_closure *closure; - void **respp; - void *args; + int ffi_closure_inner_* (cif, fun, user_data, frame) */ +ARM_FUNC_START(ffi_go_closure_SYSV, 1) + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #4] @ load cif + ldr r1, [ip, #8] @ load fun + mov r2, ip @ load user_data + b 0f + cfi_endproc +ARM_FUNC_END(ffi_go_closure_SYSV) + ARM_FUNC_START(ffi_closure_SYSV, 1) UNWIND .fnstart cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) - mov r0, ip @ load closure + ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif + ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun + ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data +0: add ip, sp, #16 @ compute entry sp - sub sp, sp, #32 @ allocate rvalue space - stmdb sp!, {sp,lr} + sub sp, sp, #64+32 @ allocate frame + cfi_adjust_cfa_offset(64+32) + stmdb sp!, {ip,lr} /* Remember that EABI unwind info only applies at call sites. We need do nothing except note the save of the stack pointer @@ -204,46 +216,53 @@ ARM_FUNC_START(ffi_closure_SYSV, 1) cfi_adjust_cfa_offset(8) cfi_rel_offset(lr, 4) - add r1, sp, #8 @ load respp - add r2, sp, #8+32 @ load args - mov r3, #0 @ load vfp_args - + add r3, sp, #8 @ load frame bl CNAME(ffi_closure_inner_SYSV) @ Load values returned in registers. - add r2, sp, #8 @ load respp + add r2, sp, #8+64 @ load result adr r3, CNAME(ffi_closure_ret) add pc, r3, r0, lsl #3 cfi_endproc UNWIND .fnend ARM_FUNC_END(ffi_closure_SYSV) +ARM_FUNC_START(ffi_go_closure_VFP, 1) + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #4] @ load cif + ldr r1, [ip, #8] @ load fun + mov r2, ip @ load user_data + b 0f + cfi_endproc +ARM_FUNC_END(ffi_go_closure_VFP) + ARM_FUNC_START(ffi_closure_VFP, 1) UNWIND .fnstart cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) - sub sp, sp, #64+32 @ allocate vfp+rvalue space + ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif + ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun + ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data +0: + add ip, sp, #16 + sub sp, sp, #64+32 @ allocate frame cfi_adjust_cfa_offset(64+32) stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7} - mov r0, ip @ load closure - add ip, sp, #16+64+32 @ compute entry sp stmdb sp!, {ip,lr} /* See above. */ UNWIND .save {sp,lr} cfi_adjust_cfa_offset(8) - cfi_rel_offset(sp, 0) cfi_rel_offset(lr, 4) - add r1, sp, #8+64 @ load respp - add r2, sp, #8+64+32 @ load args - add r3, sp, #8 @ load vfp_args - + add r3, sp, #8 @ load frame bl CNAME(ffi_closure_inner_VFP) @ Load values returned in registers. - add r2, sp, #8+64 @ load respp + add r2, sp, #8+64 @ load result adr r3, CNAME(ffi_closure_ret) add pc, r3, r0, lsl #3 cfi_endproc