add support for go closure support on mips
authorfoxsen <2503799872@qq.com>
Tue, 4 Aug 2015 04:53:33 +0000 (12:53 +0800)
committerfoxsen <2503799872@qq.com>
Tue, 4 Aug 2015 04:53:33 +0000 (12:53 +0800)
src/mips/ffi.c
src/mips/ffitarget.h
src/mips/n32.S
src/mips/o32.S

index 5d0dd70..076f1f8 100644 (file)
@@ -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 */
index 717d659..a201c92 100644 (file)
@@ -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
index c6985d3..67c82be 100644 (file)
@@ -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
index eb27981..942a2c8 100644 (file)
@@ -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.