summaryrefslogtreecommitdiff
path: root/src/alpha
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2014-10-17 21:26:52 -0700
committerRichard Henderson <rth@twiddle.net>2014-11-12 09:31:21 +0100
commit9761b7bb70b4c47dc11dc74830964a0b3b3176d3 (patch)
tree208ee9b7ae172b2a09a095dc32768e6c19a88606 /src/alpha
parentf41bec3b576aa5ff8915b1188446c2dc086dfe64 (diff)
downloadlibffi-9761b7bb70b4c47dc11dc74830964a0b3b3176d3.tar.gz
alpha: Add support for Go closures
Diffstat (limited to 'src/alpha')
-rw-r--r--src/alpha/ffi.c53
-rw-r--r--src/alpha/ffitarget.h1
-rw-r--r--src/alpha/osf.S82
3 files changed, 99 insertions, 37 deletions
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 1e5187e..efae4cc 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -41,9 +41,11 @@
# define FFI_TYPE_LONGDOUBLE 4
#endif
-extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
- FFI_HIDDEN;
+extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fn)(void), void *closure)
+ FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
+extern void ffi_go_closure_osf(void) FFI_HIDDEN;
/* Promote a float value to its in-register double representation.
Unlike actually casting to double, this does not trap on NaN. */
@@ -222,12 +224,14 @@ extend_basic_type(void *valp, int type, int argn)
}
}
-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)
{
unsigned long *argp;
long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
+ void *frame;
/* If the return value is a struct and we don't have a return
value address then we need to make one. */
@@ -236,7 +240,8 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
- argp = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ frame += cif->bytes;
argn = 0;
if (flags == ALPHA_RET_IN_MEM)
@@ -301,9 +306,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
- ffi_call_osf(argp, cif->bytes, flags, rvalue, fn);
+ ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
+}
+
+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);
+}
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
@@ -339,15 +356,31 @@ 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*))
+{
+ if (cif->abi != FFI_OSF)
+ return FFI_BAD_ABI;
+
+ closure->tramp = (void *)ffi_go_closure_osf;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
long FFI_HIDDEN
-ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
+ffi_closure_osf_inner (ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *rvalue, unsigned long *argp)
{
- ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn, argn, flags;
- cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
flags = cif->flags;
argn = 0;
@@ -481,7 +514,7 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
}
/* Invoke the closure. */
- closure->fun (cif, rvalue, avalue, closure->user_data);
+ fun (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
return (flags >> ALPHA_LD_SHIFT) & 0xff;
diff --git a/src/alpha/ffitarget.h b/src/alpha/ffitarget.h
index 60f92fd..a02dbd0 100644
--- a/src/alpha/ffitarget.h
+++ b/src/alpha/ffitarget.h
@@ -50,6 +50,7 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
diff --git a/src/alpha/osf.S b/src/alpha/osf.S
index 4059f82..b031828 100644
--- a/src/alpha/osf.S
+++ b/src/alpha/osf.S
@@ -39,10 +39,10 @@
.org 99b + \index * 16
.endm
-/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
- void *raddr, void (*fnaddr)(void));
+/* ffi_call_osf (void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fnaddr)(void), void *closure)
- Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+ Bit o trickiness here -- FRAME is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
@@ -52,22 +52,21 @@
FFI_HIDDEN(ffi_call_osf)
ffi_call_osf:
- .frame $15, 32, $26, 0
- .mask 0x4008000, -32
cfi_startproc
- addq $16,$17,$1
+ cfi_def_cfa($17, 32)
mov $16, $30
- stq $26, 0($1)
- stq $15, 8($1)
- stq $18, 16($1)
- mov $1, $15
+ stq $26, 0($17)
+ stq $15, 8($17)
+ mov $17, $15
.prologue 0
- cfi_def_cfa($15, 32)
+ cfi_def_cfa_register($15)
cfi_rel_offset($26, 0)
cfi_rel_offset($15, 8)
- stq $19, 24($1)
- mov $20, $27
+ stq $18, 16($17) # save flags into frame
+ stq $19, 24($17) # save rvalue into frame
+ mov $20, $27 # fn into place for call
+ mov $21, $1 # closure into static chain
# Load up all of the (potential) argument registers.
ldq $16, 0($30)
@@ -89,16 +88,16 @@ ffi_call_osf:
jsr $26, ($27), 0
0:
ldah $29, 0($26) !gpdisp!1
- ldq $2, 24($15)
+ ldq $2, 24($15) # reload rvalue
lda $29, 0($29) !gpdisp!1
- ldq $3, 16($15)
+ ldq $3, 16($15) # reload flags
lda $1, 99f-0b($26)
ldq $26, 0($15)
ldq $15, 8($15)
cfi_restore($26)
cfi_restore($15)
cfi_def_cfa($sp, 0)
- cmoveq $2, ALPHA_ST_VOID, $3 # mash null return to void
+ cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void
addq $3, $3, $3
s8addq $3, $1, $1 # 99f + stcode * 16
jmp $31, ($1), $st_int
@@ -136,13 +135,37 @@ E ALPHA_ST_CPLXD
#define CLOSURE_FS (16*8)
.align 4
+ .globl ffi_go_closure_osf
+ .ent ffi_go_closure_osf
+ FFI_HIDDEN(ffi_go_closure_osf)
+
+ffi_go_closure_osf:
+ cfi_startproc
+ ldgp $29, 0($27)
+ subq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(CLOSURE_FS)
+ stq $26, 0($30)
+ .prologue 1
+ cfi_rel_offset($26, 0)
+
+ stq $16, 10*8($30)
+ stq $17, 11*8($30)
+ stq $18, 12*8($30)
+
+ ldq $16, 8($1) # load cif
+ ldq $17, 16($1) # load fun
+ mov $1, $18 # closure is user_data
+ br $do_closure
+
+ cfi_endproc
+ .end ffi_go_closure_osf
+
+ .align 4
.globl ffi_closure_osf
.ent ffi_closure_osf
FFI_HIDDEN(ffi_closure_osf)
ffi_closure_osf:
- .frame $30, CLOSURE_FS, $26, 0
- .mask 0x4000000, -CLOSURE_FS
cfi_startproc
ldgp $29, 0($27)
subq $30, CLOSURE_FS, $30
@@ -152,23 +175,28 @@ ffi_closure_osf:
cfi_rel_offset($26, 0)
# Store all of the potential argument registers in va_list format.
- stt $f16, 4*8($30)
- stt $f17, 5*8($30)
- stt $f18, 6*8($30)
- stt $f19, 7*8($30)
- stt $f20, 8*8($30)
- stt $f21, 9*8($30)
stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)
+
+ ldq $16, 24($1) # load cif
+ ldq $17, 32($1) # load fun
+ ldq $18, 40($1) # load user_data
+
+$do_closure:
stq $19, 13*8($30)
stq $20, 14*8($30)
stq $21, 15*8($30)
+ stt $f16, 4*8($30)
+ stt $f17, 5*8($30)
+ stt $f18, 6*8($30)
+ stt $f19, 7*8($30)
+ stt $f20, 8*8($30)
+ stt $f21, 9*8($30)
# Call ffi_closure_osf_inner to do the bulk of the work.
- mov $1, $16
- lda $17, 2*8($30)
- lda $18, 10*8($30)
+ lda $19, 2*8($30)
+ lda $20, 10*8($30)
jsr $26, ffi_closure_osf_inner
0:
ldah $29, 0($26) !gpdisp!2