From: Andreas Tobler Date: Thu, 7 Mar 2002 18:24:42 +0000 (+0100) Subject: Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=073ae293d97f76c66767fdce57f6f6e3ef58b612;p=platform%2Fupstream%2Fgcc.git Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files. 2002-03-07 Andreas Tobler David Edelsohn * Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files. (TARGET_SRC_POWERPC_AIX): Add aix_closure.S. (TARGET_SRC_POWERPC_DARWIN): Add darwin_closure.S. * Makefile.in: Regenerate. * include/ffi.h.in: Add AIX and Darwin closure definitions. * src/powerpc/ffi_darwin.c (ffi_prep_closure): New function. (flush_icache, flush_range): New functions. (ffi_closure_helper_DARWIN): New function. * src/powerpc/aix_closure.S: New file. * src/powerpc/darwin_closure.S: New file. Co-Authored-By: David Edelsohn From-SVN: r50408 --- diff --git a/libffi/ChangeLog b/libffi/ChangeLog index ad33876..382e73b 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,17 @@ +2002-03-07 Andreas Tobler + David Edelsohn + + * Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files. + (TARGET_SRC_POWERPC_AIX): Add aix_closure.S. + (TARGET_SRC_POWERPC_DARWIN): Add darwin_closure.S. + * Makefile.in: Regenerate. + * include/ffi.h.in: Add AIX and Darwin closure definitions. + * src/powerpc/ffi_darwin.c (ffi_prep_closure): New function. + (flush_icache, flush_range): New functions. + (ffi_closure_helper_DARWIN): New function. + * src/powerpc/aix_closure.S: New file. + * src/powerpc/darwin_closure.S: New file. + 2002-02-24 Jeff Sturm * include/ffi.h.in: Add typedef for ffi_arg. diff --git a/libffi/Makefile.am b/libffi/Makefile.am index 04cc125..eece081 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -14,6 +14,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ 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/powerpc/aix_closures.S \ src/arm/ffi.c src/arm/sysv.S VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@ @@ -99,8 +100,8 @@ TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S 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_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closures.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@) diff --git a/libffi/Makefile.in b/libffi/Makefile.in index 17d8d43..f0f0348 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -95,6 +95,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ 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/powerpc/aix_closure.S \ src/arm/ffi.c src/arm/sysv.S @@ -170,8 +171,8 @@ TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S 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_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.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_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \ @@ -252,11 +253,11 @@ libfficonvenience_la_LIBADD = @POWERPC_AIX_TRUE@libfficonvenience_la_OBJECTS = src/debug.lo \ @POWERPC_AIX_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \ @POWERPC_AIX_TRUE@src/java_raw_api.lo src/powerpc/ffi_darwin.lo \ -@POWERPC_AIX_TRUE@src/powerpc/aix.lo +@POWERPC_AIX_TRUE@src/powerpc/aix.lo src/powerpc/aix_closure.lo @POWERPC_DARWIN_TRUE@libfficonvenience_la_OBJECTS = src/debug.lo \ @POWERPC_DARWIN_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \ @POWERPC_DARWIN_TRUE@src/java_raw_api.lo src/powerpc/ffi_darwin.lo \ -@POWERPC_DARWIN_TRUE@src/powerpc/darwin.lo +@POWERPC_DARWIN_TRUE@src/powerpc/darwin.lo src/powerpc/darwin_closure.lo @MIPS_SGI_TRUE@libfficonvenience_la_OBJECTS = src/debug.lo \ @MIPS_SGI_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \ @MIPS_SGI_TRUE@src/java_raw_api.lo src/mips/ffi.lo src/mips/o32.lo \ @@ -292,10 +293,12 @@ libffi_la_LIBADD = @IA64_TRUE@src/ia64/ffi.lo src/ia64/unix.lo @POWERPC_AIX_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \ @POWERPC_AIX_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ -@POWERPC_AIX_TRUE@src/powerpc/ffi_darwin.lo src/powerpc/aix.lo +@POWERPC_AIX_TRUE@src/powerpc/ffi_darwin.lo src/powerpc/aix.lo \ +@POWERPC_AIX_TRUE@src/powerpc/aix_closure.lo @POWERPC_DARWIN_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \ @POWERPC_DARWIN_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ -@POWERPC_DARWIN_TRUE@src/powerpc/ffi_darwin.lo src/powerpc/darwin.lo +@POWERPC_DARWIN_TRUE@src/powerpc/ffi_darwin.lo src/powerpc/darwin.lo \ +@POWERPC_DARWIN_TRUE@src/powerpc/darwin_closure.lo @MIPS_SGI_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \ @MIPS_SGI_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ @MIPS_SGI_TRUE@src/mips/ffi.lo src/mips/o32.lo src/mips/n32.lo diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in index 90ed269..8097917 100644 --- a/libffi/include/ffi.h.in +++ b/libffi/include/ffi.h.in @@ -412,6 +412,18 @@ struct ffi_ia64_trampoline_struct { #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 + +#elif defined(POWERPC_AIX) + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 /* see struct below */ +#define FFI_NATIVE_RAW_API 0 + #else #define FFI_CLOSURES 0 @@ -419,6 +431,16 @@ struct ffi_ia64_trampoline_struct { #endif +#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) + +struct ffi_aix_trampoline_struct { + void * code_pointer; /* Pointer to ffi_closure_ASM */ + void * toc; /* TOC */ + void * static_chain; /* Pointer to closure */ +}; + +#endif + #if FFI_CLOSURES diff --git a/libffi/src/powerpc/aix_closure.S b/libffi/src/powerpc/aix_closure.S new file mode 100644 index 0000000..7fa96f1 --- /dev/null +++ b/libffi/src/powerpc/aix_closure.S @@ -0,0 +1,251 @@ +/* ----------------------------------------------------------------------- + aix_closures.S - Copyright (c) 2002 Free Software Foundation, Inc. + based on darwin_closures.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + .set r0,0 + .set r1,1 + .set r2,2 + .set r3,3 + .set r4,4 + .set r5,5 + .set r6,6 + .set r7,7 + .set r8,8 + .set r9,9 + .set r10,10 + .set r11,11 + .set r12,12 + .set r13,13 + .set r14,14 + .set r15,15 + .set r16,16 + .set r17,17 + .set r18,18 + .set r19,19 + .set r20,20 + .set r21,21 + .set r22,22 + .set r23,23 + .set r24,24 + .set r25,25 + .set r26,26 + .set r27,27 + .set r28,28 + .set r29,29 + .set r30,30 + .set r31,31 + .set f0,0 + .set f1,1 + .set f2,2 + .set f3,3 + .set f4,4 + .set f5,5 + .set f6,6 + .set f7,7 + .set f8,8 + .set f9,9 + .set f10,10 + .set f11,11 + .set f12,12 + .set f13,13 + .set f14,14 + .set f15,15 + .set f16,16 + .set f17,17 + .set f18,18 + .set f19,19 + .set f20,20 + .set f21,21 + +#define LIBFFI_ASM +#define JUMPTARGET(name) name +#define L(x) x + .file "aix_closure.S" + .toc +LC..60: + .tc L..60[TC],L..60 + .csect .text[PR] + .align 2 + +.csect .text[PR] + .align 2 + .globl ffi_closure_ASM + .globl .ffi_closure_ASM +.csect ffi_closure_ASM[DS] + +ffi_closure_ASM: + .long .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: + + mflr r0 /* extract return address */ + stw r0, 8(r1) /* save the return address */ + + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (params) */ + /* 104 Bytes (13*8 from FPR) */ + /* 4 Bytes (result) + /* 164 Bytes */ + + stwu r1,-164(r1) /* skip over caller save area */ + +/* we want to build up an area for the parameters passed */ +/* in registers (both floating point and integer) */ + + /* we store gpr 3 to gpr 10 (aligned to 4) */ + /* in the parents outgoing area */ + stw r3, 188(r1) + stw r4, 192(r1) + stw r5, 196(r1) + stw r6, 200(r1) + stw r7, 204(r1) + stw r8, 208(r1) + stw r9, 212(r1) + stw r10, 216(r1) + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 56(r1) + stfd f2, 64(r1) + stfd f3, 72(r1) + stfd f4, 80(r1) + stfd f5, 88(r1) + stfd f6, 96(r1) + stfd f7, 104(r1) + stfd f8, 112(r1) + stfd f9, 120(r1) + stfd f10, 128(r1) + stfd f11, 136(r1) + stfd f12, 144(r1) + stfd f13, 152(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,160 + + /* now load up the pointer to the saved gpr registers */ + addi r5,r1,188 + + /* now load up the pointer to the saved fpr registers */ + addi r6,r1,56 + + /* now load up the pointer to the outgoing parameter */ + /* stack in the previous frame */ + addi r7,r1,220 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + + /* 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,160 /* get pointer to results area */ + lwz r4,LC..60(2) /* get address of jump table */ + 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 */ + +L..60: + .long L..44-L..60 /* FFI_TYPE_VOID */ + .long L..50-L..60 /* FFI_TYPE_INT */ + .long L..47-L..60 /* FFI_TYPE_FLOAT */ + .long L..46-L..60 /* FFI_TYPE_DOUBLE */ + .long L..46-L..60 /* FFI_TYPE_LONGDOUBLE */ + .long L..56-L..60 /* FFI_TYPE_UINT8 */ + .long L..55-L..60 /* FFI_TYPE_SINT8 */ + .long L..58-L..60 /* FFI_TYPE_UINT16 */ + .long L..57-L..60 /* FFI_TYPE_SINT16 */ + .long L..50-L..60 /* FFI_TYPE_UINT32 */ + .long L..50-L..60 /* FFI_TYPE_SINT32 */ + .long L..48-L..60 /* FFI_TYPE_UINT64 */ + .long L..48-L..60 /* FFI_TYPE_SINT64 */ + .long L..44-L..60 /* FFI_TYPE_STRUCT */ + .long L..50-L..60 /* FFI_TYPE_POINTER */ + + +/* case double */ +L..46: + lfd f1,0(r5) + b L..44 + +/* case float */ +L..47: + lfs f1,0(r5) + b L..44 + +/* case long long */ +L..48: + lwz r3,0(r5) + lwz r4,4(r5) + b L..44 + +/* case default / int32 / pointer */ +L..50: + lwz r3,0(r5) + b L..44 + +/* case signed int8 */ +L..55: + addi r5,r5,3 + lbz r3,0(r5) + slwi r3,r3,24 + srawi r3,r3,24 + b L..44 + +/* case unsigned int8 */ +L..56: + addi r5,r5,3 + lbz r3,0(r5) + b L..44 + +/* case signed int16 */ +L..57: + addi r5,r5,2 + lhz r3,0(r5) + extsh r3,r3 + b L..44 + +/* case unsigned int16 */ +L..58: + addi r5,r5,2 + lhz r3,0(r5) + +/* case void / done */ +L..44: + + addi r1,r1,164 /* restore stack pointer */ + lwz r0,8(r1) /* get return address */ + mtlr r0 /* reset link register */ + blr + +/* END(ffi_closure_ASM) */ diff --git a/libffi/src/powerpc/darwin_closure.S b/libffi/src/powerpc/darwin_closure.S new file mode 100644 index 0000000..9e54d22 --- /dev/null +++ b/libffi/src/powerpc/darwin_closure.S @@ -0,0 +1,189 @@ +/* ----------------------------------------------------------------------- + darwin_closures.S - Copyright (c) 2002 Free Software Foundation, Inc. + based on ppc_closures.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#define JUMPTARGET(name) name +#define L(x) x +.text +.globl _ffi_closure_helper_DARWIN + +.text + .align 2 +.globl _ffi_closure_ASM + +.text + .align 2 +_ffi_closure_ASM: + + mflr r0 /* extract return address */ + stw r0, 8(r1) /* save the return address */ + + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (outgoing parameter area, always reserved) */ + /* 104 Bytes (13*8 from FPR) */ + /* 4 Bytes (result) + /* 164 Bytes */ + + stwu r1,-164(r1) /* skip over caller save area */ + +/* we want to build up an area for the parameters passed */ +/* in registers (both floating point and integer) */ + + /* we store gpr 3 to gpr 10 (aligned to 4) */ + /* in the parents outgoing area */ + stw r3, 188(r1) + stw r4, 192(r1) + stw r5, 196(r1) + stw r6, 200(r1) + stw r7, 204(r1) + stw r8, 208(r1) + stw r9, 212(r1) + stw r10, 216(r1) + + /* we save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 56(r1) + stfd f2, 64(r1) + stfd f3, 72(r1) + stfd f4, 80(r1) + stfd f5, 88(r1) + stfd f6, 96(r1) + stfd f7, 104(r1) + stfd f8, 112(r1) + stfd f9, 120(r1) + stfd f10, 128(r1) + stfd f11, 136(r1) + stfd f12, 144(r1) + stfd f13, 152(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,160 + + /* now load up the pointer to the saved gpr registers */ + addi r5,r1,188 + + /* now load up the pointer to the saved fpr registers */ + addi r6,r1,56 + + /* now load up the pointer to the outgoing parameter */ + /* stack in the previous frame */ + addi r7,r1,220 + + /* 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,160 /* 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 */ + +.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: + + addi r1,r1,164 /* restore stack pointer */ + lwz r0,8(r1) /* get return address */ + mtlr r0 /* reset link register */ + blr + +/* END(ffi_closure_ASM) */ + diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c index 3cf504c..d80f6bf 100644 --- a/libffi/src/powerpc/ffi_darwin.c +++ b/libffi/src/powerpc/ffi_darwin.c @@ -6,7 +6,7 @@ Darwin ABI support (c) 2001 John Hornkvist AIX ABI support (c) 2002 Free Software Foundation, Inc. - $Id: ffi_darwin.c,v 1.2 2002/01/17 16:04:21 dje Exp $ + $Id: ffi_darwin.c,v 1.3 2002/02/21 19:14:28 dje Exp $ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -31,6 +31,8 @@ #include #include + +extern void ffi_closure_ASM(void); enum { /* The assembly depends on these exact flags. */ @@ -382,3 +384,328 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, break; } } + +static void flush_icache(char *); +static void flush_range(char *, int); + +/* The layout of a function descriptor. A C function pointer really */ +/* points to one of these. */ + +typedef struct aix_fd_struct { + void *code_pointer; + void *toc; +} aix_fd; + +/* here I'd like to add the stack frame layout we use in darwin_closure.S + * and aix_clsoure.S + * +/* SP previous -> +---------------------------------------+ <--- child frame + | back chain to caller 4 | + +---------------------------------------+ 4 + | saved CR 4 | + +---------------------------------------+ 8 + | saved LR 4 | + +---------------------------------------+ 12 + | reserved for compilers 4 | + +---------------------------------------+ 16 + | reserved for binders 4 | + +---------------------------------------+ 20 + | saved TOC pointer 4 | + +---------------------------------------+ 24 + | always reserved 8*4=32 (revious GPRs)| + | according to the linkage convention | + | from AIX | + +---------------------------------------+ 56 + | our FPR area 13*8=104 | + | f1 | + | . | + | f13 | + +---------------------------------------+ 160 + | result area 4 | +SP current --> +---------------------------------------+ 164 <- parent frame + | back chain to caller 4 | + +---------------------------------------+ 168 + | saved CR 4 | + +---------------------------------------+ 172 + | saved LR 4 | + +---------------------------------------+ 176 + | reserved for compilers 4 | + +---------------------------------------+ 180 + | reserved for binders 4 | + +---------------------------------------+ 184 + | saved TOC pointer 4 | + +---------------------------------------+ 188 + | always reserved 8*4=32 we store our | + | GPRs here | + | r3 | + | . | + | r10 | + +---------------------------------------+ 220 + | PST area, overflow part | + +---------------------------------------+ xxx + | ???? | + +---------------------------------------+ xxx + +*/ +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + struct ffi_aix_trampoline_struct *tramp_aix; + + switch (cif->abi) + { + case FFI_DARWIN: + + FFI_ASSERT (cif->abi == FFI_DARWIN); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x4800000d; /* bl 10 */ + 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_ASM; /* function */ + *(void **) &tramp[3] = (void *)closure; /* context */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. Only necessary on Darwin */ + flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE); + + break; + + case FFI_AIX: + + tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp); + aix_fd *fd = (aix_fd *)(void *)ffi_closure_ASM; + + FFI_ASSERT (cif->abi == FFI_AIX); + + tramp_aix->code_pointer = fd->code_pointer; + tramp_aix->toc = fd->toc; + tramp_aix->static_chain = closure; + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + default: + + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +static void +flush_icache(char *addr) +{ +#ifndef _AIX + __asm__ volatile ( + "dcbf 0,%0;" + "sync;" + "icbi 0,%0;" + "sync;" + "isync;" + : : "r"(addr) : "memory"); +#endif +} + +static 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_ASM, 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_ASM 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_ASM */ + /* pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM */ + /* 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 = (void *)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: + /* long long ints are passed in two gpr's if available or in + * the pst, one place is a bit odd, when a long long passes + * the boundary between gpr and pst area we have to increment + * the pst by one. + */ + if (ng < 7) { + avalue[i] = pgr; + ng+=2; + pgr+=2; + } else if (ng == 7) { + avalue[i] = pgr; + ng++; + pgr++; + pst++; + } else { + avalue[i] = pst; + pst+=2; + } + break; + + case FFI_TYPE_FLOAT: + /* a float value consumes a GPR + * + * there are 13 64bit floating point registers + */ + + if ((ng > 7) && (nf < 13)) { + pst++; + } + if (nf < 13) { + temp = *(double*)pfr; + *(float*)pfr = (float)temp; + avalue[i] = pfr; + nf++; + pfr+=2; + ng++; + pgr++; + + } else { + avalue[i] = pst; + nf++; + pst++; + } + break; + + case FFI_TYPE_DOUBLE: + /* a double value consumes two GPRs + * + * there are 13 64bit floating point registers + */ + + if ((ng == 7) && (nf < 13)) { + pst++; /* if only one gpr is left the double steals it */ + } else if ((ng > 7) && (nf < 13)) { + pst+=2; /* a double consumes two GPRs in Darwin/AIX */ + } + if (nf < 13) { + avalue[i] = pfr; + nf++; + pfr+=2; + ng+=2; + pgr+=2; + + } else { + avalue[i] = pst; + nf++; + pst+=2; + } + break; + + default: + FFI_ASSERT(0); + + } + + i++; + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype->type; + +}