This is the mail archive of the
libffi-discuss@sources.redhat.com
mailing list for the libffi project.
[rfc-patch] extend darwin ABI with closures in libffi
- From: Andreas Tobler <toa at pop dot agri dot ch>
- To: Libffi <libffi-discuss at sources dot redhat dot com>
- Cc: Bryce McKinlay <bryce at waitaki dot otago dot ac dot nz>, "Kevin B. Hendricks" <khendricks at ivey dot uwo dot ca>
- Date: Mon, 04 Feb 2002 17:46:03 +0100
- Subject: [rfc-patch] extend darwin ABI with closures in libffi
- Organization: zero
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) */