summaryrefslogtreecommitdiff
path: root/src/mips
diff options
context:
space:
mode:
authorfoxsen <2503799872@qq.com>2015-08-04 12:53:33 +0800
committerfoxsen <2503799872@qq.com>2015-08-04 12:53:33 +0800
commit697dd4e8a03625a9b1448aa696978d8dcc57d438 (patch)
treef0aab8a6581d87fc30381f37a235ed7c95c8afec /src/mips
parent17ffc3655a531c116e9eb9cc933e50bb1e5c47f8 (diff)
downloadlibffi-697dd4e8a03625a9b1448aa696978d8dcc57d438.tar.gz
add support for go closure support on mips
Diffstat (limited to 'src/mips')
-rw-r--r--src/mips/ffi.c78
-rw-r--r--src/mips/ffitarget.h2
-rw-r--r--src/mips/n32.S58
-rw-r--r--src/mips/o32.S87
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.