This is the mail archive of the libffi-discuss@sources.redhat.com mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[rfc-patch] extend darwin ABI with closures in libffi


Hi, 

I'd like to contribute the following patch. (Do I have to send it here
or to gcc-patches?)

It gives the darwin ABI closures. This is namely necessary when we want
to run the interpreter mode in java (gnu java, not the sun one)

The patch is a derived work from the existing
libffi/src/powerpc/ppc_closure.S/ffi.c. Here Kevin helped me a lot and
gave useful hints. Thanks.

I tested it with the ffitest, no failure so far. Now I start to test
gij. 

This submission is maybe a bit early. But in this way you may correct me
in things I do wrong.

In the ffi_darwin.c there is a trampoline code snippet. I took the one
from gcc/config/rs6000/darwin-tramp.asm, probably we could also use the tramp.asm.

Any comments?


Regards,

Andreas

2002-02-04		Andreas Tobler <a.tobler@schweiz.ch>

	* src/powerpc/darwin_closure.S: New file
	* src/powerpc/ffi_darwin.c (ffi_prep_closure): New function.
	(flush_icache): Likewise.
	(flush_range): Likewise.
	(ffi_closure_helper_DARWIN): Likewise.
	* include/ffi.h.in (FFI_CLOSURES): Define on POWERPC_DARWIN.
	(FFI_TRAMPOLINE_SIZE): Likewise.
	(FFI_NATIVE_RAW_API): Likewise.
	* Makefile.in: Rebuilt.
	* Makefile.am (EXTRA_DIST): Added src/powerpc/darwin_closure.S.
	(TARGET_SRC_ POWERPC_DARWIN): Likewise.

--- libffi/Makefile.am.orig    Sat Feb  2 14:01:14 2002
+++ libffi/Makefile.am Sat Feb  2 14:03:05 2002
@@ -14,6 +14,7 @@
                src/powerpc/ppc_closure.S src/powerpc/asm.h \
                src/powerpc/ffi_darwin.c \
                src/powerpc/darwin.S src/powerpc/aix.S \
+               src/powerpc/darwin_closure.S \
                src/arm/ffi.c src/arm/sysv.S
 
 VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@
@@ -100,7 +101,8 @@
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
 TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S
-TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S
+TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c
src/powerpc/darwin.S \
+               src/powerpc/darwin_closure.S
 TARGET_SRC_ARM =  src/arm/sysv.S src/arm/ffi.c
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)


--- libffi/include/ffi.h.in.orig        Fri Feb  1 22:36:24 2002
+++ libffi/include/ffi.h.in     Fri Feb  1 22:51:01 2002
@@ -402,6 +402,12 @@
 #define FFI_TRAMPOLINE_SIZE 40
 #define FFI_NATIVE_RAW_API 0
 
+#elif defined(POWERPC_DARWIN)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 40
+#define FFI_NATIVE_RAW_API 0
+
 #else 
 
 #define FFI_CLOSURES 0

--- libffi/src/powerpc/ffi_darwin.c.orig        Fri Feb  1 22:36:24 2002
+++ libffi/src/powerpc/ffi_darwin.c     Mon Feb  4 17:40:15 2002
@@ -31,6 +31,9 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
+#include <stdio.h>
+
+extern void ffi_closure_DARWIN(void);
 
 enum {
   /* The assembly depends on these exact flags.  */
@@ -374,3 +377,254 @@
       break;
     }
 }
+
+static void flush_range(char *, int);
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+                  ffi_cif* cif,
+                  void (*fun)(ffi_cif*, void*, void**, void*),
+                  void *user_data)
+{
+  unsigned int *tramp;
+
+  FFI_ASSERT (cif->abi == FFI_DARWIN);
+
+  tramp = (unsigned int *) &closure->tramp[0];
+  /* trampoline code borrowed from here: */
+  /* gcc/gcc/config/rs6000/darwin-tramp.asm */
+  /* to find the addresses below create a .S file and go through */
+  /* gcc -c file.S and do objdump -d file.o, then you get the */
+  /* hex values */
+  tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
+  tramp[1] = 0x4800000d;  /*   bl      10 <trampoline_initial+0x10> */
+  tramp[4] = 0x7d6802a6;  /*   mflr    r11 */
+  tramp[5] = 0x818b0000;  /*   lwz     r12,0(r11)  /* function address
*/ 
+  tramp[6] = 0x7c0803a6;  /*   mtlr    r0  */ 
+  tramp[7] = 0x7d8903a6;  /*   mtctr   r12 */
+  tramp[8] = 0x816b0004;  /*   lwz     r11,4(r11)  /* static chain */ 
+  tramp[9] = 0x4e800420;  /*   bctr */
+  *(void **) &tramp[2] = (void *)ffi_closure_DARWIN; /* function */
+  *(void **) &tramp[3] = (void *)closure;          /* context */
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* Flush the icache.  */
+  flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+
+  return FFI_OK;
+}
+
+
+void flush_icache(char *addr)
+{
+  __asm__ volatile (    
+                "dcbf 0,%0;"
+                "sync;"
+                "icbi 0,%0;"
+                "sync;" 
+                "isync;"
+                : : "r"(addr) : "memory");
+}               
+ 
+void flush_range(char * addr1, int size)
+{
+#define MIN_LINE_SIZE 32
+  int i;
+  for (i = 0; i < size; i += MIN_LINE_SIZE)
+    flush_icache(addr1+i);
+  flush_icache(addr1+size-1);
+}
+
+
+int ffi_closure_helper_DARWIN (ffi_closure*, void*, unsigned long*,
+                                     unsigned long*, unsigned long*);
+
+/* Basically the trampoline invokes ffi_closure_DARWIN, and on
+ * entry, r11 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_DARWIN invokes the
+ * following helper function to do most of the work
+ */
+
+int
+ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
+            unsigned long * pgr, unsigned long * pfr,
+            unsigned long * pst)
+{
+  /* rvalue is the pointer to space for return value in closure
assembly */
+  /* pgr is the pointer to where r3-r10 are stored in
ffi_closure_DARWIN */
+  /* pfr is the pointer to where f1-f13 are stored in
ffi_closure_DARWIN  */
+  /* pst is the pointer to outgoing parameter stack in original caller */
+
+  void **          avalue;
+  ffi_type **      arg_types;
+  long             i, avn;
+  long             nf;   /* number of floating registers already used */
+  long             ng;   /* number of general registers already used */
+  ffi_cif *        cif;
+  double           temp;
+
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
+
+  nf = 0;
+  ng = 0;
+
+  /* Copy the caller's structure return value address so that the closure
+     returns the data directly to the caller.  */
+  if (cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      rvalue = *pgr;
+      ng++;
+      pgr++;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+ 
+  /* Grab the addresses of the arguments from the stack frame.  */
+  while (i < avn)
+    {
+      switch (arg_types[i]->type)
+        {
+        case FFI_TYPE_SINT8:
+        case FFI_TYPE_UINT8:
+        /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+             avalue[i] = (((char *)pgr)+3);
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = (((char *)pst)+3);
+             pst++;
+          }
+          break;
+
+        case FFI_TYPE_SINT16:
+        case FFI_TYPE_UINT16:
+        /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+             avalue[i] = (((char *)pgr)+2);
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = (((char *)pst)+2);
+             pst++;
+          }
+          break;
+
+        case FFI_TYPE_SINT32:
+        case FFI_TYPE_UINT32:
+        case FFI_TYPE_POINTER:
+        case FFI_TYPE_STRUCT:
+        /* there are 8 gpr registers used to pass values */
+          if (ng < 8) {
+             avalue[i] = pgr;
+             ng++;
+             pgr++;
+          } else {
+             avalue[i] = pst;
+             pst++;
+          }
+          break;
+
+        case FFI_TYPE_SINT64:
+        case FFI_TYPE_UINT64:
+          /* passing long long ints are complex, they must
+           * be passed in suitable register pairs such as
+           * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
+           * and if the entire pair aren't available then the outgoing
+           * parameter stack is used for both but an alignment of 8
+           * must will be kept.  So we must either look in pgr
+           * or pst to find the correct address for this type
+           * of parameter.
+           */
+           if (ng < 7) {
+              if (ng & 0x01) {
+                /* skip r4, r6, r8 as starting points */
+                  ng++;
+                  pgr++;
+              }
+              avalue[i] = pgr;
+              ng+=2;
+              pgr+=2;
+           } else {
+              if (((long)pst) & 4) pst++;
+              avalue[i] = pst;
+              pst+=2;
+           }
+           break;
+
+        case FFI_TYPE_FLOAT:
+            /* unfortunately float values are stored as doubles
+             * in the ffi_closure_DARWIN code (since we don't check
+             * the type in that routine).  This is also true
+             * of floats passed on the outgoing parameter stack.
+             * Also, on the outgoing stack all values are aligned
+             * to 8
+             *
+             */
+
+          /* there are 13 64bit floating point registers */
+
+          if (nf < 13) {
+             temp = *(double*)pfr;
+             *(float*)pfr = (float)temp;
+             avalue[i] = pfr;
+             nf++;
+             pfr+=2;
+          } else {
+            /* FIXME? here we are really changing the values
+             * stored in the original calling routines outgoing
+             * parameter stack.  This is probably a really
+             * naughty thing to do but...
+             */
+             if (((long)pst) & 4) pst++;
+             temp = *(double*)pst;
+             *(float*)pst = (float)temp;
+             avalue[i] = pst;
+             nf++;
+             pst+=2;
+          }
+          break;
+
+        case FFI_TYPE_DOUBLE:
+          /* On the outgoing stack all values are aligned to 8 */
+          /* there are 13 64bit floating point registers */
+
+          if (nf < 13) {
+             avalue[i] = pfr;
+             nf++;
+             pfr+=2;
+          } else {
+             if (((long)pst) & 4) pst++;
+             avalue[i] = pst;
+             nf++;
+             pst+=2;
+          }
+          break;
+
+        default:
+          FFI_ASSERT(0);
+        }
+
+      i++;
+    }
+
+
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_osf how to perform return type promotions.  */
+  return cif->rtype->type;
+
+}


--- libffi/src/powerpc/darwin_closure.S.orig    Sun Feb  3 15:53:41 2002
+++ libffi/src/powerpc/darwin_closure.S Sun Feb  3 15:08:04 2002
@@ -1 +1,161 @@
+#define LIBFFI_ASM
+#define JUMPTARGET(name) name
+#define L(x) x
+.text
+.globl _ffi_closure_helper_DARWIN
+
+.text
+        .align 2
+.globl _ffi_closure_DARWIN
+
+.text
+        .align 2
+_ffi_closure_DARWIN:
+       /* store previous frame pointer */
+       stwu r1,-184(r1)
+
+       mflr r0
+       stw  r31,180(r1)
+
+       stw  r0,188(r1)
+
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+       /* so first save gpr 3 to gpr 10 (aligned to 4) */
+       stw   r3, 16(r1)
+       stw   r4, 20(r1)
+       stw   r5, 24(r1) 
+       stw   r6, 28(r1)
+       stw   r7, 32(r1)
+       stw   r8, 36(r1) 
+       stw   r9, 40(r1)
+       stw   r10,44(r1)
+
+       /* next save fpr 1 to fpr 13 (aligned to 8) */
+       stfd  f1, 48(r1)
+       stfd  f2, 56(r1)
+       stfd  f3, 64(r1)
+       stfd  f4, 72(r1)
+       stfd  f5, 80(r1)
+       stfd  f6, 88(r1)
+       stfd  f7, 96(r1)
+       stfd  f8, 104(r1)
+       stfd  f9, 112(r1) 
+       stfd  f10, 120(r1) 
+       stfd  f11, 128(r1) 
+       stfd  f12, 136(r1) 
+       stfd  f13, 144(r1) 
+
+       /* set up registers for the routine that actually does the work */
+       /* get the context pointer from the trampoline */
+       mr r3,r11
+
+        /* now load up the pointer to the result storage */
+       addi r4,r1,152
+
+       /* now load up the pointer to the saved gpr registers */
+        addi r5,r1,16
+
+        /* now load up the pointer to the saved fpr registers */
+        addi r6,r1,48
+
+       /* now load up the pointer to the outgoing parameter  */
+       /* stack in the previous frame */
+       /* i.e. the previous frame pointer + 8 */
+       addi r7,r1,192
+
+        /* make the call */
+       bl L(_ffi_closure_helper_DARWIN)
+
+       /* now r3 contains the return type */
+       /* so use it to look up in a table */
+       /* so we know how to deal with each type */
+
+        /* look up the proper starting point in table  */
+       /* by using return type as offset */
+       addi r5,r1,152   /* get pointer to results area */
+       addis r4,0,ha16(.L60)  /* get address of jump table */
+       addi r4,r4,lo16(.L60)
+       slwi r3,r3,2         /* now multiply return type by 4 */
+       lwzx r3,r4,r3         /* get the contents of that table value */
+       add r3,r3,r4          /* add contents of table to table address */
+       mtctr r3
+       bctr               /* jump to it */
+.LFE1:
+       .align 2
+.L60:
+       .long .L44-.L60    /* FFI_TYPE_VOID */
+       .long .L50-.L60    /* FFI_TYPE_INT */
+       .long .L47-.L60    /* FFI_TYPE_FLOAT */
+       .long .L46-.L60    /* FFI_TYPE_DOUBLE */
+       .long .L46-.L60    /* FFI_TYPE_LONGDOUBLE */
+       .long .L56-.L60    /* FFI_TYPE_UINT8 */
+       .long .L55-.L60    /* FFI_TYPE_SINT8 */
+       .long .L58-.L60    /* FFI_TYPE_UINT16 */
+       .long .L57-.L60    /* FFI_TYPE_SINT16 */
+       .long .L50-.L60    /* FFI_TYPE_UINT32 */
+       .long .L50-.L60    /* FFI_TYPE_SINT32 */
+       .long .L48-.L60    /* FFI_TYPE_UINT64 */
+       .long .L48-.L60    /* FFI_TYPE_SINT64 */
+       .long .L44-.L60    /* FFI_TYPE_STRUCT */
+       .long .L50-.L60    /* FFI_TYPE_POINTER */
+
+
+/* case double */
+.L46:   
+        lfd f1,0(r5)
+       b .L44
+
+/* case float */
+.L47:
+       lfs f1,0(r5)
+       b .L44
+
+/* case long long */
+.L48:
+       lwz r3,0(r5)
+       lwz r4,4(r5)
+       b .L44
+
+/* case default / int32 / pointer */
+.L50:
+       lwz r3,0(r5)
+       b .L44
+
+/* case signed int8     */
+.L55:
+       addi r5,r5,3
+       lbz r3,0(r5)
+       extsb r3,r3
+       b .L44
+
+/* case unsigned int8   */
+.L56:
+       addi r5,r5,3
+        lbz r3,0(r5)
+       b .L44
+
+/* case signed int16 */
+.L57:
+       addi r5,r5,2
+       lhz r3,0(r5)
+       extsh r3,r3
+       b .L44
+
+/* case unsigned int16 */
+.L58:
+       addi r5,r5,2
+       lhz r3,0(r5)
+
+/* case void / done     */
+.L44:
+
+       lwz r11,0(r1)
+       lwz r0,4(r11)
+       mtlr r0
+       lwz r31,-4(r11)
+       mr r1,r11
+       blr
+/* END(ffi_closure_DARWIN) */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]