Import from libffi master repository.
[gcc.git] / libffi / src / powerpc / ffi_darwin.c
index cf6fb6d4b7ca024af84d25f66c82740229b0ac42..6588e3cad0832e231b72eb70b23cc30fca11c7c0 100644 (file)
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 
 extern void ffi_closure_ASM (void);
+extern void ffi_go_closure_ASM (void);
 
 enum {
   /* The assembly depends on these exact flags.  
@@ -908,6 +909,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *,
                         void (*fn)(void), void (*fn2)(void));
 
+extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *,
+                           void (*fn)(void), void (*fn2)(void), void *closure);
+
 extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *,
                            void (*fn)(void), void (*fn2)(void), ffi_type*);
 
@@ -946,6 +950,38 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     }
 }
 
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
+            void *closure)
+{
+  extended_cif ecif;
+
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+
+  /* If the return value is a struct and we don't have a return
+     value address then we need to make one.  */
+
+  if ((rvalue == NULL) &&
+      (cif->rtype->type == FFI_TYPE_STRUCT))
+    {
+      ecif.rvalue = alloca (cif->rtype->size);
+    }
+  else
+    ecif.rvalue = rvalue;
+
+  switch (cif->abi)
+    {
+    case FFI_AIX:
+      ffi_call_go_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn,
+                     FFI_FN(ffi_prep_args), closure);
+      break;
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
 static void flush_icache(char *);
 static void flush_range(char *, int);
 
@@ -1074,6 +1110,30 @@ 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*))
+{
+  switch (cif->abi)
+    {
+      case FFI_AIX:
+
+        FFI_ASSERT (cif->abi == FFI_AIX);
+
+        closure->tramp = (void *)ffi_go_closure_ASM;
+        closure->cif = cif;
+        closure->fun = fun;
+        return FFI_OK;
+      
+      // For now, ffi_prep_go_closure is only implemented for AIX, not for Darwin
+      default:
+        return FFI_BAD_ABI;
+        break;
+    }
+  return FFI_OK;
+}
+
 static void
 flush_icache(char *addr)
 {
@@ -1108,6 +1168,10 @@ ffi_type *
 ffi_closure_helper_DARWIN (ffi_closure *, void *,
                           unsigned long *, ffi_dblfl *);
 
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure*, void *,
+                             unsigned long *, ffi_dblfl *);
+
 /* Basically the trampoline invokes ffi_closure_ASM, and on
    entry, r11 holds the address of the closure.
    After storing the registers that could possibly contain
@@ -1115,8 +1179,10 @@ ffi_closure_helper_DARWIN (ffi_closure *, void *,
    up space for a return value, ffi_closure_ASM invokes the
    following helper function to do most of the work.  */
 
-ffi_type *
-ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+static ffi_type *
+ffi_closure_helper_common (ffi_cif* cif,
+                          void (*fun)(ffi_cif*, void*, void**, void*),
+                          void *user_data, void *rvalue,
                           unsigned long *pgr, ffi_dblfl *pfr)
 {
   /* rvalue is the pointer to space for return value in closure assembly
@@ -1134,14 +1200,12 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
   void **          avalue;
   ffi_type **      arg_types;
   long             i, avn;
-  ffi_cif *        cif;
   ffi_dblfl *      end_pfr = pfr + NUM_FPR_ARG_REGISTERS;
   unsigned         size_al;
 #if defined(POWERPC_DARWIN64)
   unsigned        fpsused = 0;
 #endif
 
-  cif = closure->cif;
   avalue = alloca (cif->nargs * sizeof(void *));
 
   if (cif->rtype->type == FFI_TYPE_STRUCT)
@@ -1352,8 +1416,25 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
       i++;
     }
 
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  (fun) (cif, rvalue, avalue, user_data);
 
   /* Tell ffi_closure_ASM to perform return type promotions.  */
   return cif->rtype;
 }
+
+ffi_type *
+ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+                          unsigned long *pgr, ffi_dblfl *pfr)
+{
+  return ffi_closure_helper_common (closure->cif, closure->fun,
+                                   closure->user_data, rvalue, pgr, pfr);
+}
+
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue,
+                             unsigned long *pgr, ffi_dblfl *pfr)
+{
+  return ffi_closure_helper_common (closure->cif, closure->fun,
+                                   closure, rvalue, pgr, pfr);
+}
+