arm: Add support for Go closures
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
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