diff options
author | Richard Henderson <rth@twiddle.net> | 2014-10-17 21:26:52 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2014-11-12 09:31:21 +0100 |
commit | 9761b7bb70b4c47dc11dc74830964a0b3b3176d3 (patch) | |
tree | 208ee9b7ae172b2a09a095dc32768e6c19a88606 /src/alpha | |
parent | f41bec3b576aa5ff8915b1188446c2dc086dfe64 (diff) | |
download | libffi-9761b7bb70b4c47dc11dc74830964a0b3b3176d3.tar.gz |
alpha: Add support for Go closures
Diffstat (limited to 'src/alpha')
-rw-r--r-- | src/alpha/ffi.c | 53 | ||||
-rw-r--r-- | src/alpha/ffitarget.h | 1 | ||||
-rw-r--r-- | src/alpha/osf.S | 82 |
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 |