arm: Add support for Go closures
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user