This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
[PATCH 10/10] arm: Add support for Go closures
- From: Richard Henderson <rth at twiddle dot net>
- To: libffi-discuss at sourceware dot org
- Date: Wed, 29 Oct 2014 13:05:47 -0700
- Subject: [PATCH 10/10] arm: Add support for Go closures
- Authentication-results: sourceware.org; auth=none
- References: <1414613147-10917-1-git-send-email-rth at twiddle dot net>
---
src/arm/ffi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++---------
src/arm/ffitarget.h | 1 +
src/arm/sysv.S | 63 ++++++++++++++++++++++++++++----------------
3 files changed, 105 insertions(+), 35 deletions(-)
diff --git a/src/arm/ffi.c b/src/arm/ffi.c
index eabab47..9c8732d 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;
}
+struct closure_frame
+{
+ char vfp_space[8*8] __attribute__((aligned(8)));
+ char result[8*4];
+ char argp[];
+};
+
int FFI_HIDDEN
-ffi_closure_inner_SYSV (ffi_closure *closure, void *rvalue, char *argp)
+ffi_closure_inner_SYSV (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_SYSV (cif, rvalue, argp, avalue);
- closure->fun (cif, rvalue, avalue, closure->user_data);
+ 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 744a1e1..4f473f9 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 ce5450d..fd16589 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
--
1.9.3