diff options
author | foxsen <2503799872@qq.com> | 2015-08-04 12:53:33 +0800 |
---|---|---|
committer | foxsen <2503799872@qq.com> | 2015-08-04 12:53:33 +0800 |
commit | 697dd4e8a03625a9b1448aa696978d8dcc57d438 (patch) | |
tree | f0aab8a6581d87fc30381f37a235ed7c95c8afec /src/mips | |
parent | 17ffc3655a531c116e9eb9cc933e50bb1e5c47f8 (diff) | |
download | libffi-697dd4e8a03625a9b1448aa696978d8dcc57d438.tar.gz |
add support for go closure support on mips
Diffstat (limited to 'src/mips')
-rw-r--r-- | src/mips/ffi.c | 78 | ||||
-rw-r--r-- | src/mips/ffitarget.h | 2 | ||||
-rw-r--r-- | src/mips/n32.S | 58 | ||||
-rw-r--r-- | src/mips/o32.S | 87 |
4 files changed, 194 insertions, 31 deletions
diff --git a/src/mips/ffi.c b/src/mips/ffi.c index 5d0dd70..076f1f8 100644 --- a/src/mips/ffi.c +++ b/src/mips/ffi.c @@ -581,14 +581,15 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) /* Low level routine for calling O32 functions */ extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), extended_cif *, unsigned, - unsigned, unsigned *, void (*)(void)); + unsigned, unsigned *, void (*)(void), void *closure); /* Low level routine for calling N32 functions */ extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), extended_cif *, unsigned, - unsigned, void *, void (*)(void)); + unsigned, void *, void (*)(void), void *closure); -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +void ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { extended_cif ecif; @@ -610,7 +611,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) case FFI_O32: case FFI_O32_SOFT_FLOAT: ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); + cif->flags, ecif.rvalue, fn, closure); break; #endif @@ -642,7 +643,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) #endif } ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, - cif->flags, rvalue_copy, fn); + cif->flags, rvalue_copy, fn, closure); if (copy_rvalue) memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size); } @@ -655,6 +656,20 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) } } +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); +} + + #if FFI_CLOSURES #if defined(FFI_MIPS_O32) extern void ffi_closure_O32(void); @@ -762,17 +777,17 @@ ffi_prep_closure_loc (ffi_closure *closure, * Based on the similar routine for sparc. */ int -ffi_closure_mips_inner_O32 (ffi_closure *closure, +ffi_closure_mips_inner_O32 (ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data; void *rvalue, ffi_arg *ar, double *fpr) { - ffi_cif *cif; void **avaluep; ffi_arg *avalue; ffi_type **arg_types; int i, avn, argn, seen_int; - cif = closure->cif; avalue = alloca (cif->nargs * sizeof (ffi_arg)); avaluep = alloca (cif->nargs * sizeof (ffi_arg)); @@ -840,7 +855,7 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure, } /* Invoke the closure. */ - (closure->fun) (cif, rvalue, avaluep, closure->user_data); + fun(cif, rvalue, avaluep, user_data); if (cif->abi == FFI_O32_SOFT_FLOAT) { @@ -916,11 +931,12 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type, * */ int -ffi_closure_mips_inner_N32 (ffi_closure *closure, +ffi_closure_mips_inner_N32 (ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, void *rvalue, ffi_arg *ar, ffi_arg *fpr) { - ffi_cif *cif; void **avaluep; ffi_arg *avalue; ffi_type **arg_types; @@ -928,7 +944,6 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure, int soft_float; ffi_arg *argp; - cif = closure->cif; soft_float = cif->abi == FFI_N64_SOFT_FLOAT || cif->abi == FFI_N32_SOFT_FLOAT; avalue = alloca (cif->nargs * sizeof (ffi_arg)); @@ -1040,11 +1055,48 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure, } /* Invoke the closure. */ - (closure->fun) (cif, rvalue, avaluep, closure->user_data); + fun (cif, rvalue, avaluep, user_data); return cif->flags >> (FFI_FLAG_BITS * 8); } #endif /* FFI_MIPS_N32 */ +#if defined(FFI_MIPS_O32) +extern void ffi_closure_O32(void); +#else +extern void ffi_closure_N32(void); +#endif /* FFI_MIPS_O32 */ + +void +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*)) +{ + void * fn; + +#if defined(FFI_MIPS_O32) + if (cif->abi != FFI_O32 && cif->abi != FFI_O32_SOFT_FLOAT) + return FFI_BAD_ABI; + fn = ffi_go_closure_O32; +#else +#if _MIPS_SIM ==_ABIN32 + if (cif->abi != FFI_N32 + && cif->abi != FFI_N32_SOFT_FLOAT) + return FFI_BAD_ABI; +#else + if (cif->abi != FFI_N64 + && cif->abi != FFI_N64_SOFT_FLOAT) + return FFI_BAD_ABI; +#endif + fn = ffi_go_closure_N32; +#endif /* FFI_MIPS_O32 */ + + closure->tramp = (void *)fn; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + #endif /* FFI_CLOSURES */ diff --git a/src/mips/ffitarget.h b/src/mips/ffitarget.h index 717d659..a201c92 100644 --- a/src/mips/ffitarget.h +++ b/src/mips/ffitarget.h @@ -231,10 +231,12 @@ typedef enum ffi_abi { #if defined(FFI_MIPS_O32) #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 20 #else /* N32/N64. */ # define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 #if _MIPS_SIM==_ABI64 #define FFI_TRAMPOLINE_SIZE 52 #else diff --git a/src/mips/n32.S b/src/mips/n32.S index c6985d3..67c82be 100644 --- a/src/mips/n32.S +++ b/src/mips/n32.S @@ -37,6 +37,7 @@ #define flags a3 #define raddr a4 #define fn a5 +#define closure a6 #define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) @@ -67,6 +68,7 @@ ffi_call_N32: REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn + REG_S closure, 6*FFI_SIZEOF_ARG($fp) # closure # Allocate at least 4 words in the argstack move v0, bytes @@ -198,6 +200,9 @@ callit: # Load the function pointer REG_L t9, 5*FFI_SIZEOF_ARG($fp) + # install the static chain(t7=$15) + REG_L t7, 6*FFI_SIZEOF_ARG($fp) + # If the return value pointer is NULL, assume no return value. REG_L t5, 4*FFI_SIZEOF_ARG($fp) beqz t5, noretval @@ -406,6 +411,38 @@ epilogue: #define GP_OFF2 (0 * FFI_SIZEOF_ARG) .align 2 + .globl ffi_go_closure_N32 + .ent ffi_go_closure_N32 +ffi_go_closure_N32: + .frame $sp, SIZEOF_FRAME2, ra + .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2) + .fmask 0x00000000,0 + SUBU $sp, SIZEOF_FRAME2 + + .cpsetup t9, GP_OFF2, ffi_closure_N32 + REG_S ra, RA_OFF2($sp) # Save return address + + REG_S a0, A0_OFF2($sp) + REG_S a1, A1_OFF2($sp) + REG_S a2, A2_OFF2($sp) + REG_S a3, A3_OFF2($sp) + REG_S a4, A4_OFF2($sp) + REG_S a5, A5_OFF2($sp) + + # Call ffi_closure_mips_inner_N32 to do the real work. + LA t9, ffi_closure_mips_inner_N32 + REG_L a0, FFI_SIZE_OF_ARG($15) # cif + REG_L a1, 2*FFI_SIZE_OF_ARG($15) # fun + mov a2, t7 # userdata=closure + ADDU a3, $sp, V0_OFF2 # rvalue + ADDU a4, $sp, A0_OFF2 # ar + ADDU a5, $sp, F12_OFF2 # fpr + + b $do_closure + + .end ffi_go_closure_N32 + + .align 2 .globl ffi_closure_N32 .ent ffi_closure_N32 ffi_closure_N32: @@ -418,14 +455,25 @@ ffi_closure_N32: .cpsetup t9, GP_OFF2, ffi_closure_N32 REG_S ra, RA_OFF2($sp) # Save return address .LCFI6: - # Store all possible argument registers. If there are more than - # fit in registers, then they were stored on the stack. REG_S a0, A0_OFF2($sp) REG_S a1, A1_OFF2($sp) REG_S a2, A2_OFF2($sp) REG_S a3, A3_OFF2($sp) REG_S a4, A4_OFF2($sp) REG_S a5, A5_OFF2($sp) + + # Call ffi_closure_mips_inner_N32 to do the real work. + LA t9, ffi_closure_mips_inner_N32 + REG_L a0, FFI_TRAMPOLINE_SIZE($12) # cif + REG_L a1, FFI_TRAMPOLINE_SIZE + FFI_SIZE_OF_ARG($12) # fun + REG_L a2, FFI_TRAMPOLINE_SIZE + 2*FFI_SIZE_OF_ARG($12) # user_data + ADDU a3, $sp, V0_OFF2 + ADDU a4, $sp, A0_OFF2 + ADDU a5, $sp, F12_OFF2 + +$do_closure: + # Store all possible argument registers. If there are more than + # fit in registers, then they were stored on the stack. REG_S a6, A6_OFF2($sp) REG_S a7, A7_OFF2($sp) @@ -439,12 +487,6 @@ ffi_closure_N32: s.d $f18, F18_OFF2($sp) s.d $f19, F19_OFF2($sp) - # Call ffi_closure_mips_inner_N32 to do the real work. - LA t9, ffi_closure_mips_inner_N32 - move a0, $12 # Pointer to the ffi_closure - ADDU a1, $sp, V0_OFF2 - ADDU a2, $sp, A0_OFF2 - ADDU a3, $sp, F12_OFF2 jalr t9 # Return flags are in v0 diff --git a/src/mips/o32.S b/src/mips/o32.S index eb27981..942a2c8 100644 --- a/src/mips/o32.S +++ b/src/mips/o32.S @@ -132,6 +132,9 @@ pass_f_d: l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float call_it: + # Load the static chain pointer + REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp) + # Load the function pointer REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp) @@ -204,13 +207,15 @@ $LFE0: -8 - f14 (le low, be high) -9 - f12 (le high, be low) -10 - f12 (le low, be high) - -11 - Called function a3 save - -12 - Called function a2 save - -13 - Called function a1 save - -14 - Called function a0 save, our sp and fp point here + -11 - Called function a5 save + -12 - Called function a4 save + -13 - Called function a3 save + -14 - Called function a2 save + -15 - Called function a1 save + -16 - Called function a0 save, our sp and fp point here */ -#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG) +#define SIZEOF_FRAME2 (16 * FFI_SIZEOF_ARG) #define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG) #define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG) #define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG) @@ -225,8 +230,61 @@ $LFE0: #define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG) #define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG) #define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG) +#define CALLED_A5_OFF2 (SIZEOF_FRAME2 - 11 * FFI_SIZEOF_ARG) +#define CALLED_A4_OFF2 (SIZEOF_FRAME2 - 12 * FFI_SIZEOF_ARG) .text + + .align 2 + .globl ffi_go_closure_O32 + .ent ffi_go_closure_O32 +ffi_go_closure_O32: + # Prologue + .frame $fp, SIZEOF_FRAME2, ra + .set noreorder + .cpload t9 + .set reorder + SUBU $sp, SIZEOF_FRAME2 + .cprestore GP_OFF2 + + REG_S $16, S0_OFF2($sp) # Save s0 + REG_S $fp, FP_OFF2($sp) # Save frame pointer + REG_S ra, RA_OFF2($sp) # Save return address + + move $fp, $sp + + REG_S a0, A0_OFF2($fp) + REG_S a1, A1_OFF2($fp) + REG_S a2, A2_OFF2($fp) + REG_S a3, A3_OFF2($fp) + + # Load ABI enum to s0 + REG_L $16, 4($15) # cif + REG_L $16, 0($16) # abi is first member. + + li $13, 1 # FFI_O32 + bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT + + # Store all possible float/double registers. + s.d $f12, FA_0_0_OFF2($fp) + s.d $f14, FA_1_0_OFF2($fp) + + # prepare arguments for ffi_closure_mips_inner_O32 + REG_L a0, 4($15) # cif + REG_L a1, 8($15) # fun + mov a2, $15 # user_data = go closure + addu a3, $fp, V0_OFF2 # rvalue + + addu t9, $fp, A0_OFF2 # ar + REG_S t9, CALLED_A4_OFF2($fp) + + addu t9, $fp, FA_0_0_OFF2 #fpr + REG_S t9, CALLED_A5_OFF2($fp) + + b $do_closure + + .end ffi_go_closure_O32 + .align 2 .globl ffi_closure_O32 .ent ffi_closure_O32 @@ -265,12 +323,21 @@ $LCFI7: s.d $f12, FA_0_0_OFF2($fp) s.d $f14, FA_1_0_OFF2($fp) 1: - # Call ffi_closure_mips_inner_O32 to do the work. + # prepare arguments for ffi_closure_mips_inner_O32 + REG_L a0, 20($12) # cif pointer follows tramp. + REG_L a1, 24($12) # fun + REG_L a2, 28($12) # user_data + addu a3, $fp, V0_OFF2 # rvalue + + addu t9, $fp, A0_OFF2 # ar + REG_S t9, CALLED_A4_OFF2($fp) + + addu t9, $fp, FA_0_0_OFF2 #fpr + REG_S t9, CALLED_A5_OFF2($fp) + +$do_closure: la t9, ffi_closure_mips_inner_O32 - move a0, $12 # Pointer to the ffi_closure - addu a1, $fp, V0_OFF2 - addu a2, $fp, A0_OFF2 - addu a3, $fp, FA_0_0_OFF2 + # Call ffi_closure_mips_inner_O32 to do the work. jalr t9 # Load the return value into the appropriate register. |