arm: Add support for Go closures

This commit is contained in:
Richard Henderson
2014-10-29 14:38:42 -04:00
parent 6fa617dabc
commit ab83cbb90b
3 changed files with 106 additions and 36 deletions

View File

@@ -308,6 +308,7 @@ struct call_frame
void *lr; void *lr;
void *rvalue; void *rvalue;
int flags; int flags;
void *closure;
}; };
extern void ffi_call_SYSV (void *stack, struct call_frame *, 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 *, extern void ffi_call_VFP (void *vfp_space, struct call_frame *,
void (*fn) (void), unsigned vfp_used) FFI_HIDDEN; void (*fn) (void), unsigned vfp_used) FFI_HIDDEN;
void static void
ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue,
void **avalue, void *closure)
{ {
int flags = cif->flags; int flags = cif->flags;
ffi_type *rtype = cif->rtype; 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->rvalue = new_rvalue;
frame->flags = flags; frame->flags = flags;
frame->closure = closure;
if (vfp_space) 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); 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 * static void *
ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue, ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
char *argp, void **avalue) char *argp, void **avalue)
@@ -476,31 +492,43 @@ ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
return rvalue; return rvalue;
} }
int FFI_HIDDEN struct closure_frame
ffi_closure_inner_SYSV (ffi_closure *closure, void *rvalue, char *argp)
{ {
ffi_cif *cif = closure->cif; char vfp_space[8*8] __attribute__((aligned(8)));
void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); char result[8*4];
char argp[];
};
rvalue = ffi_prep_incoming_args_SYSV (cif, rvalue, argp, avalue); int FFI_HIDDEN
closure->fun (cif, rvalue, avalue, closure->user_data); 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; return cif->flags;
} }
int FFI_HIDDEN int FFI_HIDDEN
ffi_closure_inner_VFP (ffi_closure *closure, void *rvalue, ffi_closure_inner_VFP (ffi_cif *cif,
char *argp, char *vfp_space) 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 *)); void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp,
rvalue = ffi_prep_incoming_args_VFP (cif, rvalue, argp, vfp_space, avalue); frame->vfp_space, avalue);
closure->fun (cif, rvalue, avalue, closure->user_data); fun (cif, rvalue, avalue, user_data);
return cif->flags; return cif->flags;
} }
void ffi_closure_SYSV (void) FFI_HIDDEN; void ffi_closure_SYSV (void) FFI_HIDDEN;
void ffi_closure_VFP (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 #if FFI_EXEC_TRAMPOLINE_TABLE
@@ -785,6 +813,28 @@ ffi_prep_closure_loc (ffi_closure * closure,
return FFI_OK; 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. */ /* Below are routines for VFP hard-float support. */
/* A subroutine of vfp_type_p. Given a structure type, return the type code /* A subroutine of vfp_type_p. Given a structure type, return the type code

View File

@@ -62,6 +62,7 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */ /* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1 #define FFI_CLOSURES 1
#define FFI_GO_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_SIZE 12
#define FFI_NATIVE_RAW_API 0 #define FFI_NATIVE_RAW_API 0

View File

@@ -136,6 +136,7 @@ ARM_FUNC_START(ffi_call_SYSV, 1)
mov sp, r0 @ install the stack pointer mov sp, r0 @ install the stack pointer
mov lr, r2 @ move the fn pointer out of the way 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. ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
blx lr @ call fn blx lr @ call fn
@@ -180,22 +181,33 @@ ARM_FUNC_END(ffi_call_SYSV)
/* /*
unsigned int FFI_HIDDEN int ffi_closure_inner_* (cif, fun, user_data, frame)
ffi_closure_inner (closure, respp, args)
ffi_closure *closure;
void **respp;
void *args;
*/ */
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) ARM_FUNC_START(ffi_closure_SYSV, 1)
UNWIND .fnstart UNWIND .fnstart
cfi_startproc cfi_startproc
stmdb sp!, {r0-r3} @ save argument regs stmdb sp!, {r0-r3} @ save argument regs
cfi_adjust_cfa_offset(16) 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 add ip, sp, #16 @ compute entry sp
sub sp, sp, #32 @ allocate rvalue space sub sp, sp, #64+32 @ allocate frame
stmdb sp!, {sp,lr} cfi_adjust_cfa_offset(64+32)
stmdb sp!, {ip,lr}
/* Remember that EABI unwind info only applies at call sites. /* Remember that EABI unwind info only applies at call sites.
We need do nothing except note the save of the stack pointer 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_adjust_cfa_offset(8)
cfi_rel_offset(lr, 4) cfi_rel_offset(lr, 4)
add r1, sp, #8 @ load respp add r3, sp, #8 @ load frame
add r2, sp, #8+32 @ load args
mov r3, #0 @ load vfp_args
bl CNAME(ffi_closure_inner_SYSV) bl CNAME(ffi_closure_inner_SYSV)
@ Load values returned in registers. @ Load values returned in registers.
add r2, sp, #8 @ load respp add r2, sp, #8+64 @ load result
adr r3, CNAME(ffi_closure_ret) adr r3, CNAME(ffi_closure_ret)
add pc, r3, r0, lsl #3 add pc, r3, r0, lsl #3
cfi_endproc cfi_endproc
UNWIND .fnend UNWIND .fnend
ARM_FUNC_END(ffi_closure_SYSV) 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) ARM_FUNC_START(ffi_closure_VFP, 1)
UNWIND .fnstart UNWIND .fnstart
cfi_startproc cfi_startproc
stmdb sp!, {r0-r3} @ save argument regs stmdb sp!, {r0-r3} @ save argument regs
cfi_adjust_cfa_offset(16) 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) cfi_adjust_cfa_offset(64+32)
stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7} 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} stmdb sp!, {ip,lr}
/* See above. */ /* See above. */
UNWIND .save {sp,lr} UNWIND .save {sp,lr}
cfi_adjust_cfa_offset(8) cfi_adjust_cfa_offset(8)
cfi_rel_offset(sp, 0)
cfi_rel_offset(lr, 4) cfi_rel_offset(lr, 4)
add r1, sp, #8+64 @ load respp add r3, sp, #8 @ load frame
add r2, sp, #8+64+32 @ load args
add r3, sp, #8 @ load vfp_args
bl CNAME(ffi_closure_inner_VFP) bl CNAME(ffi_closure_inner_VFP)
@ Load values returned in registers. @ 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) adr r3, CNAME(ffi_closure_ret)
add pc, r3, r0, lsl #3 add pc, r3, r0, lsl #3
cfi_endproc cfi_endproc