dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dotgnu-pnet-commits] pnet ChangeLog libffi/ChangeLog libffi/Makefile...


From: Klaus Treichel
Subject: [dotgnu-pnet-commits] pnet ChangeLog libffi/ChangeLog libffi/Makefile...
Date: Fri, 30 Nov 2007 20:59:58 +0000

CVSROOT:        /cvsroot/dotgnu-pnet
Module name:    pnet
Changes by:     Klaus Treichel <ktreichel>      07/11/30 20:59:58

Modified files:
        .              : ChangeLog 
        libffi         : ChangeLog Makefile.am README configure.ac 
        libffi/include : Makefile.am ffi.h.in ffi_common.h 
        libffi/src     : debug.c java_raw_api.c prep_cif.c raw_api.c 
                         types.c 
        libffi/src/alpha: ffi.c ffitarget.h osf.S 
        libffi/src/arm : ffi.c ffitarget.h sysv.S 
        libffi/src/cris: ffi.c 
        libffi/src/frv : eabi.S ffi.c 
        libffi/src/ia64: ffi.c 
        libffi/src/m32r: ffi.c 
        libffi/src/m68k: ffi.c ffitarget.h sysv.S 
        libffi/src/mips: ffi.c ffitarget.h n32.S o32.S 
        libffi/src/pa  : ffi.c ffitarget.h linux.S 
        libffi/src/powerpc: ffi.c ffi_darwin.c ffitarget.h linux64.S 
                            ppc_closure.S sysv.S 
        libffi/src/s390: ffi.c 
        libffi/src/sh  : ffi.c sysv.S 
        libffi/src/sh64: ffi.c sysv.S 
        libffi/src/sparc: ffi.c 
        libffi/src/x86 : ffi.c ffi64.c ffitarget.h sysv.S 
Added files:
        libffi/src     : closures.c dlmalloc.c 
        libffi/src/pa  : hpux32.S 
        libffi/src/x86 : darwin.S darwin64.S 
Removed files:
        libffi/src     : ffitest.c 

Log message:
        Update libffi

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pnet/ChangeLog?cvsroot=dotgnu-pnet&r1=1.3519&r2=1.3520
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/ChangeLog?cvsroot=dotgnu-pnet&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/Makefile.am?cvsroot=dotgnu-pnet&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/README?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/configure.ac?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/include/Makefile.am?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/include/ffi.h.in?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/include/ffi_common.h?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/debug.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/java_raw_api.c?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/prep_cif.c?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/raw_api.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/types.c?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/closures.c?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/dlmalloc.c?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/ffitest.c?cvsroot=dotgnu-pnet&r1=1.3&r2=0
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/alpha/ffi.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/alpha/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/alpha/osf.S?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/arm/ffi.c?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/arm/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/arm/sysv.S?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/cris/ffi.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/frv/eabi.S?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/frv/ffi.c?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/ia64/ffi.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/m32r/ffi.c?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/m68k/ffi.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/m68k/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/m68k/sysv.S?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/mips/ffi.c?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/mips/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/mips/n32.S?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/mips/o32.S?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/pa/ffi.c?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/pa/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/pa/linux.S?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/pa/hpux32.S?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/ffi.c?cvsroot=dotgnu-pnet&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/ffi_darwin.c?cvsroot=dotgnu-pnet&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/linux64.S?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/ppc_closure.S?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/powerpc/sysv.S?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/s390/ffi.c?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/sh/ffi.c?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/sh/sysv.S?cvsroot=dotgnu-pnet&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/sh64/ffi.c?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/sh64/sysv.S?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/sparc/ffi.c?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/ffi.c?cvsroot=dotgnu-pnet&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/ffi64.c?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/ffitarget.h?cvsroot=dotgnu-pnet&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/sysv.S?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/darwin.S?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnet/libffi/src/x86/darwin64.S?cvsroot=dotgnu-pnet&rev=1.1

Patches:
Index: ChangeLog
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/ChangeLog,v
retrieving revision 1.3519
retrieving revision 1.3520
diff -u -b -r1.3519 -r1.3520
--- ChangeLog   29 Nov 2007 20:16:50 -0000      1.3519
+++ ChangeLog   30 Nov 2007 20:59:54 -0000      1.3520
@@ -1,3 +1,29 @@
+2007-11-30  Klaus Treichel  <address@hidden>
+
+       * libffi/ChangeLog, libffi/Makefile.am, libffi/README,
+       libffi/configure.ac, libffi/include/Makefile.am, 
libffi/include/ffi.h.in,
+       libffi/include/ffi_common.h, libffi/src/debug.c,
+       libffi/src/java_raw_api.c, libffi/src/prep_cif.c, libffi/src/raw_api.c,
+       libffi/src/types.c, libffi/src/alpha/ffi.c, 
libffi/src/alpha/ffitarget.h,
+       libffi/src/alpha/osf.S, libffi/src/arm/ffi.c, 
libffi/src/arm/ffitarget.h,
+       libffi/src/arm/sysv.S, libffi/src/cris/ffi.c, libffi/src/frv/eabi.S,
+       libffi/src/frv/ffi.c, libffi/src/ia64/ffi.c, libffi/src/m32r/ffi.c,
+       libffi/src/m68k/ffi.c, libffi/src/m68k/ffitarget.h, 
libffi/src/m68k/sysv.S,
+       libffi/src/mips/ffi.c, libffi/src/mips/ffitarget.h, 
libffi/src/mips/n32.S,
+       libffi/src/mips/o32.S, libffi/src/pa/ffi.c, libffi/src/pa/ffitarget.h,
+       libffi/src/pa/linux.S, libffi/src/powerpc/ffi.c,
+       libffi/src/powerpc/ffi_darwin.c, libffi/src/powerpc/ffitarget.h,
+       libffi/src/powerpc/linux64.S, libffi/src/powerpc/ppc_closure.S,
+       libffi/src/powerpc/sysv.S, libffi/src/s390/ffi.c, libffi/src/sh/ffi.c,
+       libffi/src/sh/sysv.S, libffi/src/sh64/ffi.c, libffi/src/sh64/sysv.S,
+       libffi/src/sparc/ffi.c, libffi/src/x86/ffi.c, libffi/src/x86/ffi64.c,
+       libffi/src/x86/ffitarget.h, libffi/src/x86/sysv.S: Update libffi
+
+       * libffi/src/closures.c, libffi/src/dlmalloc.c, libffi/src/pa/hpux32.S,
+       libffi/src/x86/darwin.S, libffi/src/x86/darwin64.S: Add new libffi 
files.
+
+       * libffi/src/ffitest.c: Delete obsolete libffi file.
+
 2007-11-29  Klaus Treichel  <address@hidden>
 
        * cscc/csharp/cs_stmt.tc: Attach the type of the constant to the value

Index: libffi/ChangeLog
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/ChangeLog,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- libffi/ChangeLog    19 Dec 2005 07:07:56 -0000      1.10
+++ libffi/ChangeLog    30 Nov 2007 20:59:54 -0000      1.11
@@ -1,3 +1,935 @@
+2007-11-25  Andreas Tobler  <address@hidden>
+
+       * src/closures.c: Move defintion of MAYBE_UNUSED from here to ...
+       * include/ffi_common.h: ... here.
+       Update copyright.
+
+2007-11-17  Andreas Tobler  <address@hidden>
+
+       * src/powerpc/sysv.S: Load correct cr to compare if we have long double.
+       * src/powerpc/linux64.S: Likewise.
+       * src/powerpc/ffi.c: Add a comment to show which part goes into cr6.
+       * testsuite/libffi.call/return_ldl.c: New test.
+
+2007-09-04    <address@hidden>
+
+       * src/arm/sysv.S (UNWIND): New.
+       (Whole file): Conditionally compile unwinder directives.
+       * src/arm/sysv.S: Add unwinder directives.
+
+       * src/arm/ffi.c (ffi_prep_args): Align structs by at least 4 bytes.
+       Only treat r0 as a struct address if we're actually returning a
+       struct by address.
+       Only copy the bytes that are actually within a struct.
+       (ffi_prep_cif_machdep): A Composite Type not larger than 4 bytes
+       is returned in r0, not passed by address.
+       (ffi_call): Allocate a word-sized temporary for the case where
+       a composite is returned in r0.
+       (ffi_prep_incoming_args_SYSV): Align as necessary.
+
+2007-08-05  Steven Newbury  <address@hidden>
+
+       * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Use __clear_cache instead of 
+       directly using the sys_cacheflush syscall.
+
+2007-07-27  Andrew Haley  <address@hidden>
+
+       * src/arm/sysv.S (ffi_closure_SYSV): Add soft-float.
+
+2007-09-03  Maciej W. Rozycki  <address@hidden>
+
+       * Makefile.am: Unify MIPS_IRIX and MIPS_LINUX into MIPS.
+       * configure.ac: Likewise.
+       * Makefile.in: Regenerate.
+       * include/Makefile.in: Likewise.
+       * testsuite/Makefile.in: Likewise.
+       * configure: Likewise.
+
+2007-08-24  David Daney  <address@hidden>
+
+       * testsuite/libffi.call/return_sl.c: New test.
+
+2007-08-10  David Daney  <address@hidden>
+
+       * testsuite/libffi.call/cls_multi_ushort.c,
+       testsuite/libffi.call/cls_align_uint16.c,
+       testsuite/libffi.call/nested_struct1.c,
+       testsuite/libffi.call/nested_struct3.c,
+       testsuite/libffi.call/cls_7_1_byte.c,
+       testsuite/libffi.call/nested_struct5.c,
+       testsuite/libffi.call/cls_double.c,
+       testsuite/libffi.call/nested_struct7.c,
+       testsuite/libffi.call/cls_sint.c,
+       testsuite/libffi.call/nested_struct9.c,
+       testsuite/libffi.call/cls_20byte1.c,
+       testsuite/libffi.call/cls_multi_sshortchar.c,
+       testsuite/libffi.call/cls_align_sint64.c,
+       testsuite/libffi.call/cls_3byte2.c,
+       testsuite/libffi.call/cls_multi_schar.c,
+       testsuite/libffi.call/cls_multi_uchar.c,
+       testsuite/libffi.call/cls_19byte.c,
+       testsuite/libffi.call/cls_9byte1.c,
+       testsuite/libffi.call/cls_align_float.c,
+       testsuite/libffi.call/closure_fn1.c,
+       testsuite/libffi.call/problem1.c,
+       testsuite/libffi.call/closure_fn3.c,
+       testsuite/libffi.call/cls_sshort.c,
+       testsuite/libffi.call/closure_fn5.c,
+       testsuite/libffi.call/cls_align_double.c,
+       testsuite/libffi.call/nested_struct.c,
+       testsuite/libffi.call/cls_2byte.c,
+       testsuite/libffi.call/nested_struct10.c,
+       testsuite/libffi.call/cls_4byte.c,
+       testsuite/libffi.call/cls_6byte.c,
+       testsuite/libffi.call/cls_8byte.c,
+       testsuite/libffi.call/cls_multi_sshort.c,
+       testsuite/libffi.call/cls_align_sint16.c,
+       testsuite/libffi.call/cls_align_uint32.c,
+       testsuite/libffi.call/cls_20byte.c,
+       testsuite/libffi.call/cls_float.c,
+       testsuite/libffi.call/nested_struct2.c,
+       testsuite/libffi.call/cls_5_1_byte.c,
+       testsuite/libffi.call/nested_struct4.c,
+       testsuite/libffi.call/cls_24byte.c,
+       testsuite/libffi.call/nested_struct6.c,
+       testsuite/libffi.call/cls_64byte.c,
+       testsuite/libffi.call/nested_struct8.c,
+       testsuite/libffi.call/cls_uint.c,
+       testsuite/libffi.call/cls_multi_ushortchar.c,
+       testsuite/libffi.call/cls_schar.c,
+       testsuite/libffi.call/cls_uchar.c,
+       testsuite/libffi.call/cls_align_uint64.c,
+       testsuite/libffi.call/cls_ulonglong.c,
+       testsuite/libffi.call/cls_align_longdouble.c,
+       testsuite/libffi.call/cls_1_1byte.c,
+       testsuite/libffi.call/cls_12byte.c,
+       testsuite/libffi.call/cls_3_1byte.c,
+       testsuite/libffi.call/cls_3byte1.c,
+       testsuite/libffi.call/cls_4_1byte.c,
+       testsuite/libffi.call/cls_6_1_byte.c,
+       testsuite/libffi.call/cls_16byte.c,
+       testsuite/libffi.call/cls_18byte.c,
+       testsuite/libffi.call/closure_fn0.c,
+       testsuite/libffi.call/cls_9byte2.c,
+       testsuite/libffi.call/closure_fn2.c,
+       testsuite/libffi.call/closure_fn4.c,
+       testsuite/libffi.call/cls_ushort.c,
+       testsuite/libffi.call/closure_fn6.c,
+       testsuite/libffi.call/cls_5byte.c,
+       testsuite/libffi.call/cls_align_pointer.c,
+       testsuite/libffi.call/cls_7byte.c,
+       testsuite/libffi.call/cls_align_sint32.c,
+       testsuite/libffi.special/unwindtest_ffi_call.cc,
+       testsuite/libffi.special/unwindtest.cc: Remove xfail for mips64*-*-*.
+
+2007-08-10  David Daney  <address@hidden>
+
+       PR libffi/28313
+       * configure.ac: Don't treat mips64 as a special case.
+       * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S.
+       * configure: Regenerate
+       * Makefile.in: Ditto.
+       * fficonfig.h.in: Ditto.
+       * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent.
+       (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros.
+       (FFI_DEFAULT_ABI): Set for n64 case.
+       (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases.
+       * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE.
+       (ffi_closure_N32): New function.
+       (.eh_frame): New section
+       * src/mips/o32.S: Clean up comments.
+       (ffi_closure_O32): Pass ffi_closure parameter in $12.
+       * src/mips/ffi.c: Use FFI_MIPS_N32 instead of
+       _MIPS_SIM == _ABIN32 throughout.
+       (FFI_MIPS_STOP_HERE): New, use in place of
+       ffi_stop_here.
+       (ffi_prep_args): Use unsigned long to hold pointer values.  Rewrite
+       to support n32/n64 ABIs.
+       (calc_n32_struct_flags): Rewrite.
+       (calc_n32_return_struct_flags): Remove unused variable.  Reverse
+       position of flag bits.
+       (ffi_prep_cif_machdep): Rewrite n32 portion.
+       (ffi_call): Enable for n64.  Add special handling for small structure
+       return values.
+       (ffi_prep_closure_loc): Add n32 and n64 support.
+       (ffi_closure_mips_inner_O32): Add cast to silence warning.
+       (copy_struct_N32, ffi_closure_mips_inner_N32): New functions.
+
+2007-08-08  David Daney  <address@hidden>
+
+       * testsuite/libffi.call/ffitest.h (ffi_type_mylong): Remove definition.
+       * testsuite/libffi.call/cls_align_uint16.c (main): Use correct type
+       specifiers.
+       * testsuite/libffi.call/nested_struct1.c (main): Ditto.
+       * testsuite/libffi.call/cls_sint.c (main): Ditto.
+       * testsuite/libffi.call/nested_struct9.c (main): Ditto.
+       * testsuite/libffi.call/cls_20byte1.c (main): Ditto.
+       * testsuite/libffi.call/cls_9byte1.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn1.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn3.c (main): Ditto.
+       * testsuite/libffi.call/return_dbl2.c (main): Ditto.
+       * testsuite/libffi.call/cls_sshort.c (main): Ditto.
+       * testsuite/libffi.call/return_fl3.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn5.c (main): Ditto.
+       * testsuite/libffi.call/nested_struct.c (main): Ditto.
+       * testsuite/libffi.call/nested_struct10.c (main): Ditto.
+       * testsuite/libffi.call/return_ll1.c (main): Ditto.
+       * testsuite/libffi.call/cls_8byte.c (main): Ditto.
+       * testsuite/libffi.call/cls_align_uint32.c (main): Ditto.
+       * testsuite/libffi.call/cls_align_sint16.c (main): Ditto.
+       * testsuite/libffi.call/cls_20byte.c (main): Ditto.
+       * testsuite/libffi.call/nested_struct2.c (main): Ditto.
+       * testsuite/libffi.call/cls_24byte.c (main): Ditto.
+       * testsuite/libffi.call/nested_struct6.c (main): Ditto.
+       * testsuite/libffi.call/cls_uint.c (main): Ditto.
+       * testsuite/libffi.call/cls_12byte.c (main): Ditto.
+       * testsuite/libffi.call/cls_16byte.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn0.c (main): Ditto.
+       * testsuite/libffi.call/cls_9byte2.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn2.c (main): Ditto.
+       * testsuite/libffi.call/return_dbl1.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn4.c (main): Ditto.
+       * testsuite/libffi.call/closure_fn6.c (main): Ditto.
+       * testsuite/libffi.call/cls_align_sint32.c (main): Ditto.
+
+2007-08-07  Andrew Haley  <address@hidden>
+
+       * src/x86/sysv.S (ffi_closure_raw_SYSV): Fix typo in previous
+       checkin.
+
+2007-08-06  Andrew Haley  <address@hidden>
+
+       PR testsuite/32843
+       * src/x86/sysv.S (ffi_closure_raw_SYSV): Handle FFI_TYPE_UINT8,
+       FFI_TYPE_SINT8, FFI_TYPE_UINT16, FFI_TYPE_SINT16, FFI_TYPE_UINT32,
+       FFI_TYPE_SINT32.
+
+2007-08-02  David Daney  <address@hidden>
+
+       * testsuite/libffi.call/return_ul.c (main): Define return type as
+       ffi_arg.  Use proper printf conversion specifier.
+       
+2007-07-30  Andrew Haley  <address@hidden>
+
+       PR testsuite/32843
+       * src/x86/ffi.c (ffi_prep_cif_machdep): in x86 case, add code for
+       signed/unsigned int8/16.
+       * src/x86/sysv.S (ffi_call_SYSV): Rewrite to:
+       Use a jump table.
+       Remove code to pop args from the stack after call.
+       Special-case signed/unsigned int8/16.
+       * testsuite/libffi.call/return_sc.c (main): Revert.
+
+2007-07-26  Richard Guenther  <address@hidden>
+
+       PR testsuite/32843
+       * testsuite/libffi.call/return_sc.c (main): Verify call
+       result as signed char, not ffi_arg.
+
+2007-07-16  Rainer Orth  <address@hidden>
+
+       * configure.ac (i?86-*-solaris2.1[0-9]): Set TARGET to X86_64.
+       * configure: Regenerate.
+
+2007-07-11  David Daney  <address@hidden>
+
+       * src/mips/ffi.c: Don't include sys/cachectl.h.
+       (ffi_prep_closure_loc): Use __builtin___clear_cache() instead of
+       cacheflush().
+
+2007-05-18  Aurelien Jarno  <address@hidden>
+
+       * src/arm/ffi.c (ffi_prep_closure_loc): Renamed and ajusted
+       from (ffi_prep_closure): ... this.
+       (FFI_INIT_TRAMPOLINE): Adjust.
+
+2005-12-31  Phil Blundell  <address@hidden>
+
+       * src/arm/ffi.c (ffi_prep_incoming_args_SYSV, 
+        ffi_closure_SYSV_inner, ffi_prep_closure): New, add closure support.
+       * src/arm/sysv.S(ffi_closure_SYSV): Likewise.
+       * src/arm/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise.
+       (FFI_CLOSURES): Enable closure support.
+
+2007-07-03  Andrew Haley  <address@hidden>
+
+        * testsuite/libffi.call/cls_multi_ushort.c,
+        testsuite/libffi.call/cls_align_uint16.c,
+        testsuite/libffi.call/nested_struct1.c,
+        testsuite/libffi.call/nested_struct3.c,
+        testsuite/libffi.call/cls_7_1_byte.c,
+        testsuite/libffi.call/cls_double.c,
+        testsuite/libffi.call/nested_struct5.c,
+        testsuite/libffi.call/nested_struct7.c,
+        testsuite/libffi.call/cls_sint.c,
+        testsuite/libffi.call/nested_struct9.c,
+        testsuite/libffi.call/cls_20byte1.c,
+        testsuite/libffi.call/cls_multi_sshortchar.c,
+        testsuite/libffi.call/cls_align_sint64.c,
+        testsuite/libffi.call/cls_3byte2.c,
+        testsuite/libffi.call/cls_multi_schar.c,
+        testsuite/libffi.call/cls_multi_uchar.c,
+        testsuite/libffi.call/cls_19byte.c,
+        testsuite/libffi.call/cls_9byte1.c,
+        testsuite/libffi.call/cls_align_float.c,
+        testsuite/libffi.call/closure_fn1.c,
+        testsuite/libffi.call/problem1.c,
+        testsuite/libffi.call/closure_fn3.c,
+        testsuite/libffi.call/cls_sshort.c,
+        testsuite/libffi.call/closure_fn5.c,
+        testsuite/libffi.call/cls_align_double.c,
+        testsuite/libffi.call/cls_2byte.c,
+        testsuite/libffi.call/nested_struct.c,
+        testsuite/libffi.call/nested_struct10.c,
+        testsuite/libffi.call/cls_4byte.c,
+        testsuite/libffi.call/cls_6byte.c,
+        testsuite/libffi.call/cls_8byte.c,
+        testsuite/libffi.call/cls_multi_sshort.c,
+        testsuite/libffi.call/cls_align_uint32.c,
+        testsuite/libffi.call/cls_align_sint16.c,
+        testsuite/libffi.call/cls_float.c,
+        testsuite/libffi.call/cls_20byte.c,
+        testsuite/libffi.call/cls_5_1_byte.c,
+        testsuite/libffi.call/nested_struct2.c,
+        testsuite/libffi.call/cls_24byte.c,
+        testsuite/libffi.call/nested_struct4.c,
+        testsuite/libffi.call/nested_struct6.c,
+        testsuite/libffi.call/cls_64byte.c,
+        testsuite/libffi.call/nested_struct8.c,
+        testsuite/libffi.call/cls_uint.c,
+        testsuite/libffi.call/cls_multi_ushortchar.c,
+        testsuite/libffi.call/cls_schar.c,
+        testsuite/libffi.call/cls_uchar.c,
+        testsuite/libffi.call/cls_align_uint64.c,
+        testsuite/libffi.call/cls_ulonglong.c,
+        testsuite/libffi.call/cls_align_longdouble.c,
+        testsuite/libffi.call/cls_1_1byte.c,
+        testsuite/libffi.call/cls_12byte.c,
+        testsuite/libffi.call/cls_3_1byte.c,
+        testsuite/libffi.call/cls_3byte1.c,
+        testsuite/libffi.call/cls_4_1byte.c,
+        testsuite/libffi.call/cls_6_1_byte.c,
+        testsuite/libffi.call/cls_16byte.c,
+        testsuite/libffi.call/cls_18byte.c,
+        testsuite/libffi.call/closure_fn0.c,
+        testsuite/libffi.call/cls_9byte2.c,
+        testsuite/libffi.call/closure_fn2.c,
+        testsuite/libffi.call/closure_fn4.c,
+        testsuite/libffi.call/cls_ushort.c,
+        testsuite/libffi.call/closure_fn6.c,
+        testsuite/libffi.call/cls_5byte.c,
+        testsuite/libffi.call/cls_align_pointer.c,
+        testsuite/libffi.call/cls_7byte.c,
+        testsuite/libffi.call/cls_align_sint32.c,
+        testsuite/libffi.special/unwindtest_ffi_call.cc,
+        testsuite/libffi.special/unwindtest.cc: Enable for ARM.
+
+2007-07-05  H.J. Lu  <address@hidden>
+
+       * aclocal.m4: Regenerated.
+
+2007-06-02  Paolo Bonzini  <address@hidden>
+
+       * configure: Regenerate.
+
+2007-05-23  Steve Ellcey  <address@hidden>
+
+       * Makefile.in: Regenerate.
+       * configure: Regenerate.
+       * aclocal.m4: Regenerate.
+       * include/Makefile.in: Regenerate.
+       * testsuite/Makefile.in: Regenerate.
+
+2007-05-10  Roman Zippel <address@hidden>
+
+       * src/m68k/ffi.c (ffi_prep_incoming_args_SYSV,
+       ffi_closure_SYSV_inner,ffi_prep_closure): New, add closure support.
+       * src/m68k/sysv.S(ffi_closure_SYSV,ffi_closure_struct_SYSV): Likewise.
+       * src/m68k/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise.
+       (FFI_CLOSURES): Enable closure support.
+
+2007-05-10  Roman Zippel <address@hidden>
+
+       * configure.ac (HAVE_AS_CFI_PSEUDO_OP): New test.
+       * configure: Regenerate.
+       * fficonfig.h.in: Regenerate.
+       * src/m68k/sysv.S (CFI_STARTPROC,CFI_ENDPROC,
+       CFI_OFFSET,CFI_DEF_CFA): New macros.
+       (ffi_call_SYSV): Add callframe annotation.
+
+2007-05-10  Roman Zippel <address@hidden>
+
+       * src/m68k/ffi.c (ffi_prep_args,ffi_prep_cif_machdep): Fix
+       numerous test suite failures.
+       * src/m68k/sysv.S (ffi_call_SYSV): Likewise.
+
+2007-04-11  Paolo Bonzini  <address@hidden>
+
+       * Makefile.am (EXTRA_DIST): Bring up to date.
+       * Makefile.in: Regenerate.
+       * src/frv/eabi.S: Remove RCS keyword.
+
+2007-04-06  Richard Henderson  <address@hidden>
+
+       * configure.ac: Tidy target case.
+       (HAVE_LONG_DOUBLE): Allow the target to override.
+       * configure: Regenerate.
+       * include/ffi.h.in: Don't define ffi_type_foo if
+       LIBFFI_HIDE_BASIC_TYPES is defined.
+       (ffi_type_longdouble): If not HAVE_LONG_DOUBLE, define
+       to ffi_type_double.
+       * types.c (LIBFFI_HIDE_BASIC_TYPES): Define.
+       (FFI_TYPEDEF, ffi_type_void): Mark the data const.
+       (ffi_type_longdouble): Special case for Alpha.  Don't define
+       if long double == double.
+
+       * src/alpha/ffi.c (FFI_TYPE_LONGDOUBLE): Assert unique value.
+       (ffi_prep_cif_machdep): Handle it as the 128-bit type.
+       (ffi_call, ffi_closure_osf_inner): Likewise.
+       (ffi_closure_osf_inner): Likewise.  Mark hidden.
+       (ffi_call_osf, ffi_closure_osf): Mark hidden.
+       * src/alpha/ffitarget.h (FFI_LAST_ABI): Tidy definition.
+       * src/alpha/osf.S (ffi_call_osf, ffi_closure_osf): Mark hidden.
+       (load_table): Handle 128-bit long double.
+
+       * testsuite/libffi.call/float4.c: Add -mieee for alpha.
+
+2007-04-06  Tom Tromey  <address@hidden>
+
+       PR libffi/31491:
+       * README: Fixed bug in example.
+
+2007-04-03  Jakub Jelinek  <address@hidden>
+
+       * src/closures.c: Include sys/statfs.h.
+       (_GNU_SOURCE): Define on Linux.
+       (FFI_MMAP_EXEC_SELINUX): Define.
+       (selinux_enabled): New variable.
+       (selinux_enabled_check): New function.
+       (is_selinux_enabled): Define.
+       (dlmmap): Use it.
+
+2007-03-24  Uros Bizjak  <address@hidden>
+
+       * testsuite/libffi.call/return_fl2.c (return_fl): Mark as static.
+       Use 'volatile float sum' to create sum of floats to avoid false
+       negative due to excess precision on ix86 targets.
+       (main): Ditto. 
+
+2007-03-08  Alexandre Oliva  <address@hidden>
+
+       * src/powerpc/ffi.c (flush_icache): Fix left-over from previous
+       patch.
+       (ffi_prep_closure_loc): Remove unneeded casts.  Add needed ones.
+
+2007-03-07  Alexandre Oliva  <address@hidden>
+
+       * include/ffi.h.in (ffi_closure_alloc, ffi_closure_free): New.
+       (ffi_prep_closure_loc): New.
+       (ffi_prep_raw_closure_loc): New.
+       (ffi_prep_java_raw_closure_loc): New.
+       * src/closures.c: New file.
+       * src/dlmalloc.c [FFI_MMAP_EXEC_WRIT] (struct malloc_segment):
+       Replace sflags with exec_offset.
+       [FFI_MMAP_EXEC_WRIT] (mmap_exec_offset, add_segment_exec_offset,
+       sub_segment_exec_offset): New macros.
+       (get_segment_flags, set_segment_flags, check_segment_merge): New
+       macros.
+       (is_mmapped_segment, is_extern_segment): Use get_segment_flags.
+       (add_segment, sys_alloc, create_mspace, create_mspace_with_base,
+       destroy_mspace): Use new macros.
+       (sys_alloc): Silence warning.
+       * Makefile.am (libffi_la_SOURCES): Add src/closures.c.
+       * Makefile.in: Rebuilt.
+       * src/prep_cif [FFI_CLOSURES] (ffi_prep_closure): Implement in
+       terms of ffi_prep_closure_loc.
+       * src/raw_api.c (ffi_prep_raw_closure_loc): Renamed and adjusted
+       from...
+       (ffi_prep_raw_closure): ... this.  Re-implement in terms of the
+       renamed version.
+       * src/java_raw_api (ffi_prep_java_raw_closure_loc): Renamed and
+       adjusted from...
+       (ffi_prep_java_raw_closure): ... this.  Re-implement in terms of
+       the renamed version.
+       * src/alpha/ffi.c (ffi_prep_closure_loc): Renamed from
+       (ffi_prep_closure): ... this.
+       * src/pa/ffi.c: Likewise.
+       * src/cris/ffi.c: Likewise.  Adjust.
+       * src/frv/ffi.c: Likewise.
+       * src/ia64/ffi.c: Likewise.
+       * src/mips/ffi.c: Likewise.
+       * src/powerpc/ffi_darwin.c: Likewise.
+       * src/s390/ffi.c: Likewise.
+       * src/sh/ffi.c: Likewise.
+       * src/sh64/ffi.c: Likewise.
+       * src/sparc/ffi.c: Likewise.
+       * src/x86/ffi64.c: Likewise.
+       * src/x86/ffi.c: Likewise.
+       (FFI_INIT_TRAMPOLINE): Adjust.
+       (ffi_prep_raw_closure_loc): Renamed and adjusted from...
+       (ffi_prep_raw_closure): ... this.
+       * src/powerpc/ffi.c (ffi_prep_closure_loc): Renamed from
+       (ffi_prep_closure): ... this.
+       (flush_icache): Adjust.
+
+2007-03-07  Alexandre Oliva  <address@hidden>
+
+       * src/dlmalloc.c: New file, imported version 2.8.3 of Doug
+       Lea's malloc.
+
+2007-03-01  Brooks Moses  <address@hidden>
+
+       * Makefile.am: Add dummy install-pdf target.
+       * Makefile.in: Regenerate
+
+2007-02-13  Andreas Krebbel  <address@hidden>
+
+       * src/s390/ffi.c (ffi_prep_args, ffi_prep_cif_machdep,
+       ffi_closure_helper_SYSV): Add long double handling.
+
+2007-02-02  Jakub Jelinek  <address@hidden>
+
+       * src/powerpc/linux64.S (ffi_call_LINUX64): Move restore of r2
+       immediately after bctrl instruction.
+
+2007-01-18  Alexandre Oliva  <address@hidden>
+
+       * Makefile.am (all-recursive, install-recursive,
+       mostlyclean-recursive, clean-recursive, distclean-recursive,
+       maintainer-clean-recursive): Add missing targets.
+       * Makefile.in: Rebuilt.
+
+2006-12-14  Andreas Tobler  <address@hidden>
+
+       * configure.ac: Add TARGET for x86_64-*-darwin*.
+       * Makefile.am (nodist_libffi_la_SOURCES): Add rules for 64-bit sources
+       for X86_DARWIN.
+       * src/x86/ffitarget.h: Set trampoline size for x86_64-*-darwin*.
+       * src/x86/darwin64.S: New file for x86_64-*-darwin* support.
+       * configure: Regenerate.
+       * Makefile.in: Regenerate.
+       * include/Makefile.in: Regenerate.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/libffi.special/unwindtest_ffi_call.cc: New test case for
+       ffi_call only.
+
+2006-12-13  Andreas Tobler <address@hidden>
+
+       * aclocal.m4: Regenerate with aclocal -I .. as written in the
+       Makefile.am.
+
+2006-10-31  Geoffrey Keating  <address@hidden>
+
+       * src/powerpc/ffi_darwin.c (darwin_adjust_aggregate_sizes): New.
+       (ffi_prep_cif_machdep): Call darwin_adjust_aggregate_sizes for
+       Darwin.
+       * testsuite/libffi.call/nested_struct4.c: Remove Darwin XFAIL.
+       * testsuite/libffi.call/nested_struct6.c: Remove Darwin XFAIL.
+
+2006-10-10  Paolo Bonzini  <address@hidden>
+           Sandro Tolaini  <address@hidden>
+
+       * configure.ac [i*86-*-darwin*]: Set X86_DARWIN symbol and 
+       conditional.
+       * configure: Regenerated.
+       * Makefile.am (nodist_libffi_la_SOURCES) [X86_DARWIN]: New case.
+       (EXTRA_DIST): Add src/x86/darwin.S.
+       * Makefile.in: Regenerated.
+       * include/Makefile.in: Regenerated.
+       * testsuite/Makefile.in: Regenerated.
+
+       * src/x86/ffi.c (ffi_prep_cif_machdep) [X86_DARWIN]: Treat like
+       X86_WIN32, and additionally align stack to 16 bytes.
+       * src/x86/darwin.S: New, based on sysv.S.
+       * src/prep_cif.c (ffi_prep_cif) [X86_DARWIN]: Align > 8-byte structs.
+
+2006-09-12  David Daney  <address@hidden>
+
+       PR libffi/23935
+       * include/Makefile.am: Install both ffi.h and ffitarget.h in
+       $(libdir)/gcc/$(target_alias)/$(gcc_version)/include.
+       * aclocal.m4: Regenerated for automake 1.9.6.
+       * Makefile.in: Regenerated.
+       * include/Makefile.in: Regenerated.
+       * testsuite/Makefile.in: Regenerated.
+
+2006-08-17  Andreas Tobler  <address@hidden>
+
+       * include/ffi_common.h (struct): Revert accidental commit.
+
+2006-08-15  Andreas Tobler  <address@hidden>
+
+       * include/ffi_common.h: Remove lint directives.
+       * include/ffi.h.in: Likewise.
+
+2006-07-25  Torsten Schoenfeld  <address@hidden>
+
+       * include/ffi.h.in (ffi_type_ulong, ffi_type_slong): Define correctly
+       for 32-bit architectures.
+       * testsuite/libffi.call/return_ul.c: New test case.
+
+2006-07-19  David Daney  <address@hidden>
+
+       * testsuite/libffi.call/closure_fn6.c: Remove xfail for mips,
+       xfail remains for mips64.
+
+2006-05-23  Carlos O'Donell  <address@hidden>
+
+       * Makefile.am: Add install-html target. Add install-html to .PHONY
+       * Makefile.in: Regenerate.
+       * aclocal.m4: Regenerate.
+       * include/Makefile.in: Regenerate.
+       * testsuite/Makefile.in: Regenerate.
+
+2006-05-18  John David Anglin  <address@hidden>
+
+       * pa/ffi.c (ffi_prep_args_pa32): Load floating point arguments from
+       stack slot.
+
+2006-04-22  Andreas Tobler  <address@hidden>
+
+       * README: Remove notice about 'Crazy Comments'.
+       * src/debug.c: Remove lint directives. Cleanup white spaces.
+       * src/java_raw_api.c: Likewise.
+       * src/prep_cif.c: Likewise.
+       * src/raw_api.c: Likewise.
+       * src/ffitest.c: Delete. No longer needed, all test cases migrated
+       to the testsuite.
+       * src/arm/ffi.c: Remove lint directives.
+       * src/m32r/ffi.c: Likewise.
+       * src/pa/ffi.c: Likewise.
+       * src/powerpc/ffi.c: Likewise.
+       * src/powerpc/ffi_darwin.c: Likewise.
+       * src/sh/ffi.c: Likewise.
+       * src/sh64/ffi.c: Likewise.
+       * src/x86/ffi.c: Likewise.
+       * testsuite/libffi.call/float2.c: Likewise.
+       * testsuite/libffi.call/promotion.c: Likewise.
+       * testsuite/libffi.call/struct1.c: Likewise.
+
+2006-04-13  Andreas Tobler  <address@hidden>
+
+       * src/pa/hpux32.S: Correct unwind offset calculation for
+       ffi_closure_pa32.
+       * src/pa/linux.S: Likewise.
+
+2006-04-12  James E Wilson  <address@hidden>
+
+       PR libgcj/26483
+       * src/ia64/ffi.c (stf_spill, ldf_fill): Rewrite as macros.
+       (hfa_type_load): Call stf_spill.
+       (hfa_type_store): Call ldf_fill.
+       (ffi_call): Adjust calls to above routines.  Add local temps for
+       macro result.
+
+2006-04-10  Matthias Klose  <address@hidden>
+
+       * testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib
+       directory names containing underscores.
+
+2006-04-07  James E Wilson  <address@hidden>
+
+       * testsuite/libffi.call/float4.c: New testcase.
+
+2006-04-05  John David Anglin  <address@hidden>
+           Andreas Tobler  <address@hidden>
+
+       * Makefile.am: Add PA_HPUX port.
+       * Makefile.in: Regenerate.
+       * include/Makefile.in: Likewise.
+       * testsuite/Makefile.in: Likewise.
+       * configure.ac: Add PA_HPUX rules.
+       * configure: Regenerate.
+       * src/pa/ffitarget.h: Rename linux target to PA_LINUX.
+       Add PA_HPUX and PA64_HPUX.
+       Rename FFI_LINUX ABI to FFI_PA32 ABI.
+       (FFI_TRAMPOLINE_SIZE): Define for 32-bit HP-UX targets.
+       (FFI_TYPE_SMALL_STRUCT2): Define.
+       (FFI_TYPE_SMALL_STRUCT4): Likewise.
+       (FFI_TYPE_SMALL_STRUCT8): Likewise.
+       (FFI_TYPE_SMALL_STRUCT3): Redefine.
+       (FFI_TYPE_SMALL_STRUCT5): Likewise.
+       (FFI_TYPE_SMALL_STRUCT6): Likewise.
+       (FFI_TYPE_SMALL_STRUCT7): Likewise.
+       * src/pa/ffi.c (ROUND_DOWN): Delete.
+       (fldw, fstw, fldd, fstd): Use '__asm__'.
+       (ffi_struct_type): Add support for FFI_TYPE_SMALL_STRUCT2,
+       FFI_TYPE_SMALL_STRUCT4 and FFI_TYPE_SMALL_STRUCT8.
+       (ffi_prep_args_LINUX): Rename to ffi_prep_args_pa32. Update comment.
+       Simplify incrementing of stack slot variable. Change type of local
+       'n' to unsigned int.
+       (ffi_size_stack_LINUX): Rename to ffi_size_stack_pa32. Handle long
+       double on PA_HPUX.
+       (ffi_prep_cif_machdep): Likewise.
+       (ffi_call): Likewise.
+       (ffi_closure_inner_LINUX): Rename to ffi_closure_inner_pa32. Change
+       return type to ffi_status. Simplify incrementing of stack slot
+       variable. Only copy floating point argument registers when PA_LINUX
+       is true. Reformat debug statement.
+       Add support for FFI_TYPE_SMALL_STRUCT2, FFI_TYPE_SMALL_STRUCT4 and
+       FFI_TYPE_SMALL_STRUCT8.
+       (ffi_closure_LINUX): Rename to ffi_closure_pa32. Add 'extern' to
+       declaration.
+       (ffi_prep_closure): Make linux trampoline conditional on PA_LINUX.
+       Add nops to cache flush.  Add trampoline for PA_HPUX.
+       * src/pa/hpux32.S: New file.
+       * src/pa/linux.S (ffi_call_LINUX): Rename to ffi_call_pa32. Rename
+       ffi_prep_args_LINUX to ffi_prep_args_pa32.
+       Localize labels. Add support for 2, 4 and 8-byte small structs. Handle
+       unaligned destinations in 3, 5, 6 and 7-byte small structs. Order
+       argument type checks so that common argument types appear first.
+       (ffi_closure_LINUX): Rename to ffi_closure_pa32. Rename
+       ffi_closure_inner_LINUX to ffi_closure_inner_pa32.
+
+2006-03-24  Alan Modra  <address@hidden>
+
+       * src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX.  Default
+       for 32-bit using IBM extended double format.  Fix FFI_LAST_ABI.
+       * src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
+       FFI_TYPE_LONGDOUBLE.
+       (ffi_prep_args64): Assert using IBM extended double.
+       (ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
+       Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
+       (ffi_call): Handle FFI_LINUX.
+       (ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
+       gpr3 return pointer as for struct return.  Handle FFI_LINUX
+       FFI_TYPE_LONGDOUBLE return and args.  Don't increment "nf"
+       unnecessarily.
+       * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
+       for FFI_TYPE_LONGDOUBLE.  Move epilogue insns into case table.
+       Don't use r6 as pointer to results, instead use sp offset.  Don't
+       make a special call to load lr with case table address, instead
+       use offset from previous call.
+       * src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
+       * src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
+       return.
+
+2006-03-15  Kaz Kojima  <address@hidden>
+
+       * src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments
+       passed with FP registers correctly.
+       (ffi_closure_helper_SYSV): Likewise.
+       * src/sh64/sysv.S: Likewise.
+
+2006-03-01  Andreas Tobler  <address@hidden>
+
+       * testsuite/libffi.special/unwindtest.cc (closure_test_fn): Mark cif,
+       args and userdata unused.
+       (closure_test_fn1): Mark cif and userdata unused.
+       (main): Remove unused res.
+
+2006-02-28  Andreas Tobler  <address@hidden>
+
+       * testsuite/libffi.call/call.exp: Adjust FSF address. Add test runs for
+       -O2, -O3, -Os and the warning flags -W -Wall.
+       * testsuite/libffi.special/special.exp: Likewise.
+       * testsuite/libffi.call/ffitest.h: Add an __UNUSED__ macro to mark
+       unused parameter unused for gcc or else do nothing.
+       * testsuite/libffi.special/ffitestcxx.h: Likewise.
+       * testsuite/libffi.call/cls_12byte.c (cls_struct_12byte_gn): Mark cif
+       and userdata unused.
+       * testsuite/libffi.call/cls_16byte.c (cls_struct_16byte_gn): Likewise.
+       * testsuite/libffi.call/cls_18byte.c (cls_struct_18byte_gn): Likewise.
+       * testsuite/libffi.call/cls_19byte.c (cls_struct_19byte_gn): Likewise.
+       * testsuite/libffi.call/cls_1_1byte.c (cls_struct_1_1byte_gn): Likewise.
+       * testsuite/libffi.call/cls_20byte.c (cls_struct_20byte_gn): Likewise.
+       * testsuite/libffi.call/cls_20byte1.c (cls_struct_20byte_gn): Likewise.
+       * testsuite/libffi.call/cls_24byte.c (cls_struct_24byte_gn): Likewise.
+       * testsuite/libffi.call/cls_2byte.c (cls_struct_2byte_gn): Likewise.
+       * testsuite/libffi.call/cls_3_1byte.c (cls_struct_3_1byte_gn): Likewise.
+       * testsuite/libffi.call/cls_3byte1.c (cls_struct_3byte_gn): Likewise.
+       * testsuite/libffi.call/cls_3byte2.c (cls_struct_3byte_gn1): Likewise.
+       * testsuite/libffi.call/cls_4_1byte.c (cls_struct_4_1byte_gn): Likewise.
+       * testsuite/libffi.call/cls_4byte.c (cls_struct_4byte_gn): Likewise.
+       * testsuite/libffi.call/cls_5_1_byte.c (cls_struct_5byte_gn): Likewise.
+       * testsuite/libffi.call/cls_5byte.c (cls_struct_5byte_gn): Likewise.
+       * testsuite/libffi.call/cls_64byte.c (cls_struct_64byte_gn): Likewise.
+       * testsuite/libffi.call/cls_6_1_byte.c (cls_struct_6byte_gn): Likewise.
+       * testsuite/libffi.call/cls_6byte.c (cls_struct_6byte_gn): Likewise.
+       * testsuite/libffi.call/cls_7_1_byte.c (cls_struct_7byte_gn): Likewise.
+       * testsuite/libffi.call/cls_7byte.c (cls_struct_7byte_gn): Likewise.
+       * testsuite/libffi.call/cls_8byte.c (cls_struct_8byte_gn): Likewise.
+       * testsuite/libffi.call/cls_9byte1.c (cls_struct_9byte_gn): Likewise.
+       * testsuite/libffi.call/cls_9byte2.c (cls_struct_9byte_gn): Likewise.
+       * testsuite/libffi.call/cls_align_double.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_float.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_longdouble.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_pointer.c (cls_struct_align_fn): Cast
+       void* to avoid compiler warning.
+       (main): Likewise.
+       (cls_struct_align_gn): Mark cif and userdata unused.
+       * testsuite/libffi.call/cls_align_sint16.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_sint32.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_sint64.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_uint16.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_align_uint32.c (cls_struct_align_gn):
+       Likewise.
+       * testsuite/libffi.call/cls_double.c (cls_ret_double_fn): Likewise.
+       * testsuite/libffi.call/cls_float.c (cls_ret_float_fn): Likewise.
+       * testsuite/libffi.call/cls_multi_schar.c (test_func_gn): Mark cif and
+       data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_multi_sshort.c (test_func_gn): Mark cif and
+       data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_multi_sshortchar.c (test_func_gn): Mark cif
+       and data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_multi_uchar.c (test_func_gn): Mark cif and
+       data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_multi_ushort.c (test_func_gn): Mark cif and
+       data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_multi_ushortchar.c (test_func_gn): Mark cif
+       and data unused.
+       (main): Cast res_call to silence gcc.
+       * testsuite/libffi.call/cls_schar.c (cls_ret_schar_fn): Mark cif and
+       userdata unused.
+       (cls_ret_schar_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/cls_sint.c (cls_ret_sint_fn): Mark cif and
+       userdata unused.
+       (cls_ret_sint_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/cls_sshort.c (cls_ret_sshort_fn): Mark cif and
+       userdata unused.
+       (cls_ret_sshort_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/cls_uchar.c (cls_ret_uchar_fn):  Mark cif and
+       userdata unused.
+       (cls_ret_uchar_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/cls_uint.c (cls_ret_uint_fn): Mark cif and
+       userdata unused.
+       (cls_ret_uint_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/cls_ulonglong.c (cls_ret_ulonglong_fn): Mark cif
+       and userdata unused.
+       * testsuite/libffi.call/cls_ushort.c (cls_ret_ushort_fn): Mark cif and
+       userdata unused.
+       (cls_ret_ushort_fn): Cast printf parameter to silence gcc.
+       * testsuite/libffi.call/float.c (floating): Remove unused parameter e.
+       * testsuite/libffi.call/float1.c (main): Remove unused variable i.
+       Cleanup white spaces.
+       * testsuite/libffi.call/negint.c (checking): Remove unused variable i.
+       * testsuite/libffi.call/nested_struct.c (cls_struct_combined_gn): Mark
+       cif and userdata unused.
+       * testsuite/libffi.call/nested_struct1.c (cls_struct_combined_gn):
+       Likewise.
+       * testsuite/libffi.call/nested_struct10.c (B_gn): Likewise.
+       * testsuite/libffi.call/nested_struct2.c (B_fn): Adjust printf
+       formatters to silence gcc.
+       (B_gn): Mark cif and userdata unused.
+       * testsuite/libffi.call/nested_struct3.c (B_gn): Mark cif and userdata
+       unused.
+       * testsuite/libffi.call/nested_struct4.c: Mention related PR.
+       (B_gn): Mark cif and userdata unused.
+       * testsuite/libffi.call/nested_struct5.c (B_gn): Mark cif and userdata
+       unused.
+       * testsuite/libffi.call/nested_struct6.c: Mention related PR.
+       (B_gn): Mark cif and userdata unused.
+       * testsuite/libffi.call/nested_struct7.c (B_gn): Mark cif and userdata
+       unused.
+       * testsuite/libffi.call/nested_struct8.c (B_gn): Likewise.
+       * testsuite/libffi.call/nested_struct9.c (B_gn): Likewise.
+       * testsuite/libffi.call/problem1.c (stub): Likewise.
+       * testsuite/libffi.call/pyobjc-tc.c (main): Cast the result to silence
+       gcc.
+       * testsuite/libffi.call/return_fl2.c (return_fl): Add the note mentioned
+       in the last commit for this test case in the test case itself.
+       * testsuite/libffi.call/closure_fn0.c (closure_test_fn0): Mark cif as
+       unused.
+       * testsuite/libffi.call/closure_fn1.c (closure_test_fn1): Likewise.
+       * testsuite/libffi.call/closure_fn2.c (closure_test_fn2): Likewise.
+       * testsuite/libffi.call/closure_fn3.c (closure_test_fn3): Likewise.
+       * testsuite/libffi.call/closure_fn4.c (closure_test_fn0): Likewise.
+       * testsuite/libffi.call/closure_fn5.c (closure_test_fn5): Likewise.
+       * testsuite/libffi.call/closure_fn6.c (closure_test_fn0): Likewise.
+
+2006-02-22  Kaz Kojima  <address@hidden>
+
+       * src/sh/sysv.S: Fix register numbers in the FDE for
+       ffi_closure_SYSV.
+
+2006-02-20  Andreas Tobler  <address@hidden>
+
+       * testsuite/libffi.call/return_fl2.c (return_fl): Remove static
+       declaration to avoid a false negative on ix86. See PR323.
+
+2006-02-18  Kaz Kojima  <address@hidden>
+
+       * src/sh/ffi.c (ffi_closure_helper_SYSV): Remove unused variable
+       and cast integer to void * if needed.  Update the pointer to
+       the FP register saved area correctly.
+       
+2006-02-17  Andreas Tobler  <address@hidden>
+
+       * testsuite/libffi.call/nested_struct6.c: XFAIL this test until PR25630
+       is fixed.
+       * testsuite/libffi.call/nested_struct4.c: Likewise.
+
+2006-02-16  Andreas Tobler  <address@hidden>
+
+       * testsuite/libffi.call/return_dbl.c: New test case.
+       * testsuite/libffi.call/return_dbl1.c: Likewise.
+       * testsuite/libffi.call/return_dbl2.c: Likewise.
+       * testsuite/libffi.call/return_fl.c: Likewise.
+       * testsuite/libffi.call/return_fl1.c: Likewise.
+       * testsuite/libffi.call/return_fl2.c: Likewise.
+       * testsuite/libffi.call/return_fl3.c: Likewise.
+       * testsuite/libffi.call/closure_fn6.c: Likewise.
+
+       * testsuite/libffi.call/nested_struct2.c: Remove ffi_type_mylong
+       definition.
+       * testsuite/libffi.call/ffitest.h: Add ffi_type_mylong definition
+       here to be used by other test cases too.
+
+       * testsuite/libffi.call/nested_struct10.c: New test case.
+       * testsuite/libffi.call/nested_struct9.c: Likewise.
+       * testsuite/libffi.call/nested_struct8.c: Likewise.
+       * testsuite/libffi.call/nested_struct7.c: Likewise.
+       * testsuite/libffi.call/nested_struct6.c: Likewise.
+       * testsuite/libffi.call/nested_struct5.c: Likewise.
+       * testsuite/libffi.call/nested_struct4.c: Likewise.
+
+2006-01-21  Andreas Tobler  <address@hidden>
+
+       * configure.ac: Enable libffi for sparc64-*-freebsd*.
+       * configure: Rebuilt.
+
+2006-01-18  Jakub Jelinek  <address@hidden>
+
+       * src/powerpc/sysv.S (smst_two_register): Don't call __ashldi3,
+       instead do the shifting inline.
+       * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Don't compute %r5
+       shift count unconditionally.  Simplify load sequences for 1, 2, 3, 4
+       and 8 byte structs, for the remaining struct sizes don't call
+       __lshrdi3, instead do the shifting inline.
+
+2005-12-07  Thiemo Seufer  <address@hidden>
+
+       * src/mips/ffitarget.h: Remove obsolete sgidefs.h include. Add
+       missing parentheses.
+       * src/mips/o32.S (ffi_call_O32): Code formatting. Define
+       and use A3_OFF, FP_OFF, RA_OFF. Micro-optimizations.
+       (ffi_closure_O32): Likewise, but with newly defined A3_OFF2,
+       A2_OFF2, A1_OFF2, A0_OFF2, RA_OFF2, FP_OFF2, S0_OFF2, GP_OFF2,
+       V1_OFF2, V0_OFF2, FA_1_1_OFF2, FA_1_0_OFF2, FA_0_1_OFF2,
+       FA_0_0_OFF2.
+       * src/mips/ffi.c (ffi_prep_args): Code formatting. Fix
+       endianness bugs.
+       (ffi_prep_closure): Improve trampoline instruction scheduling.
+       (ffi_closure_mips_inner_O32): Fix endianness bugs.
+
+2005-12-03  Alan Modra  <address@hidden>
+
+       * src/powerpc/ffi.c: Formatting.
+       (ffi_prep_args_SYSV): Avoid possible aliasing problems by using unions.
+       (ffi_prep_args64): Likewise.
+
 2005-09-30  Geoffrey Keating  <address@hidden>
 
        * testsuite/lib/libffi-dg.exp (libffi_target_compile): For

Index: libffi/Makefile.am
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/Makefile.am,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- libffi/Makefile.am  18 Feb 2007 13:31:32 -0000      1.10
+++ libffi/Makefile.am  30 Nov 2007 20:59:54 -0000      1.11
@@ -5,11 +5,13 @@
 
 SUBDIRS = include 
 
-EXTRA_DIST = LICENSE ChangeLog.v1 \
-       configure.host libtool-version \
+EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \
+       libtool-version src/dlmalloc.c \
        src/alpha/ffi.c src/alpha/osf.S src/alpha/ffitarget.h \
        src/arm/ffi.c src/arm/sysv.S src/arm/ffitarget.h \
        src/cris/ffi.c src/cris/sysv.S src/cris/ffitarget.h \
+       src/ia64/ffi.c src/ia64/ffitarget.h src/ia64/ia64_flags.h \
+       src/ia64/unix.S \
        src/mips/ffi.c src/mips/n32.S src/mips/o32.S \
        src/mips/ffitarget.h \
        src/m32r/ffi.c src/m32r/sysv.S src/m32r/ffitarget.h \
@@ -25,9 +27,10 @@
        src/sh64/ffi.c src/sh64/sysv.S src/sh64/ffitarget.h \
        src/sparc/v8.S src/sparc/v9.S src/sparc/ffitarget.h \
        src/sparc/ffi.c \
-       src/x86/ffi.c src/x86/sysv.S src/x86/win32.S \
+       src/x86/ffi.c src/x86/sysv.S src/x86/win32.S src/x86/darwin.S \
        src/x86/ffi64.c src/x86/unix64.S src/x86/ffitarget.h \
-       src/pa/ffi.c src/pa/linux.S src/frv/eabi.S src/frv/ffitarget.h
+       src/pa/ffitarget.h src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \
+       src/frv/ffi.c src/frv/eabi.S src/frv/ffitarget.h
 
 ## ################################################################
 
@@ -35,10 +38,6 @@
 ## This section is for make and multilib madness.
 ##
 
-# FIXME RSC: find out about the reason for the stuff below. Because if
-# it is in, 'make distcheck' doesn't work any more because it looses
-# it's destdir.
-
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
 # friends when we are called from the top level Makefile.
@@ -82,22 +81,22 @@
 noinst_LTLIBRARIES = libffi_convenience.la
 
 libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c \
-               src/raw_api.c src/java_raw_api.c
+               src/raw_api.c src/java_raw_api.c src/closures.c
 
 nodist_libffi_la_SOURCES =
 
-if MIPS_IRIX
+if MIPS
 nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 endif
-if MIPS_LINUX
-nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S
-endif
 if X86
 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
 endif
 if X86_WIN32
 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win32.S
 endif
+if X86_DARWIN
+nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c 
src/x86/darwin64.S
+endif
 if SPARC
 nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
 endif
@@ -146,9 +145,12 @@
 if SH64
 nodist_libffi_la_SOURCES += src/sh64/sysv.S src/sh64/ffi.c
 endif
-if PA
+if PA_LINUX
 nodist_libffi_la_SOURCES += src/pa/linux.S src/pa/ffi.c
 endif
+if PA_HPUX
+nodist_libffi_la_SOURCES += src/pa/hpux32.S src/pa/ffi.c
+endif
 
 libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
 nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
@@ -160,15 +162,15 @@
 AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src
 AM_CCASFLAGS = $(AM_CPPFLAGS)
 
-+MAINTAINERCLEANFILES = \
-       configure \
-       Makefile.in \
-       compile \
-       install-sh \
-       config.sub \
-       mkinstalldirs \
-       missing \
-       ltmain.sh \
-       depcomp \
-       config.guess
-
+# No install-html or install-pdf support in automake yet
+.PHONY: install-html install-pdf
+install-html:
+install-pdf:
+
+# Multilib support.  Automake should provide these on its own.
+# all-recursive: all-multi
+# install-recursive: install-multi
+# mostlyclean-recursive: mostlyclean-multi
+# clean-recursive: clean-multi
+# distclean-recursive: distclean-multi
+# maintainer-clean-recursive: maintainer-clean-multi

Index: libffi/README
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/README,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/README       30 Jul 2005 19:00:13 -0000      1.4
+++ libffi/README       30 Nov 2007 20:59:54 -0000      1.5
@@ -212,7 +212,7 @@
       int rc;
       
       /* Initialize the argument info vectors */    
-      args[0] = &ffi_type_uint;
+      args[0] = &ffi_type_pointer;
       values[0] = &s;
       
       /* Initialize the cif */
@@ -372,15 +372,6 @@
 arguments' test).
 
 
-What's With The Crazy Comments?
-===============================
-
-You might notice a number of cryptic comments in the code, delimited
-by /*@ and @*/. These are annotations read by the program LCLint, a
-tool for statically checking C programs. You can read all about it at
-<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>.
-
-
 History
 =======
 

Index: libffi/configure.ac
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/configure.ac,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/configure.ac 18 Feb 2007 13:31:32 -0000      1.4
+++ libffi/configure.ac 30 Nov 2007 20:59:54 -0000      1.5
@@ -41,48 +41,108 @@
 
 TARGETDIR="unknown"
 case "$host" in
-i*86-*-linux*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-gnu*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-solaris2.1[[0-9]]*) TARGET=X86_64; TARGETDIR=x86;;
-i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-beos*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-freebsd* | i*86-*-kfreebsd*-gnu) TARGET=X86; TARGETDIR=x86;;
-i*86-*-netbsdelf* | i*86-*-knetbsd*-gnu) TARGET=X86; TARGETDIR=x86;;
-i*86-*-rtems*) TARGET=X86; TARGETDIR=x86;;
-i*86-*-win32*) TARGET=X86_WIN32; TARGETDIR=x86;;
-i*86-*-cygwin*) TARGET=X86_WIN32; TARGETDIR=x86;;
-i*86-*-mingw*) TARGET=X86_WIN32; TARGETDIR=x86;;
-frv-*-*) TARGET=FRV; TARGETDIR=frv;;
-sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc*-sun-*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc-*-linux* | sparc-*-netbsdelf* | sparc-*-knetbsd*-gnu) TARGET=SPARC; 
TARGETDIR=sparc;;
-sparc*-*-rtems*) TARGET=SPARC; TARGETDIR=sparc;;
-sparc64-*-linux* | sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) TARGET=SPARC; 
TARGETDIR=sparc;;
-alpha*-*-linux* | alpha*-*-osf* | alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | 
alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) TARGET=ALPHA; TARGETDIR=alpha;;
-ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
-m32r*-*-linux* ) TARGET=M32R; TARGETDIR=m32r;;
-m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
-mips64*-*);;
-mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips;;
-mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
-powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
-powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
-powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
-powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;;
-powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;;
-rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
-arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
-arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) TARGET=ARM; TARGETDIR=arm;;
-arm*-*-rtems*) TARGET=ARM; TARGETDIR=arm;;
-cris-*-*) TARGET=LIBFFI_CRIS; TARGETDIR=cris;;
-s390-*-linux-*) TARGET=S390; TARGETDIR=s390;;
-s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;;
-x86_64-*-linux* | x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) TARGET=X86_64; 
TARGETDIR=x86;;
-sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;;
-sh-*-rtems*) TARGET=SH; TARGETDIR=sh;;
-sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;;
-hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;;
+  alpha*-*-*)
+       TARGET=ALPHA; TARGETDIR=alpha;
+       # Support 128-bit long double, changable via command-line switch.
+       HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
+       ;;
+
+  arm*-*-*)
+       TARGET=ARM; TARGETDIR=arm
+       ;;
+
+  cris-*-*)
+       TARGET=LIBFFI_CRIS; TARGETDIR=cris
+       ;;
+
+  frv-*-*)
+       TARGET=FRV; TARGETDIR=frv
+       ;;
+
+  hppa*-*-linux* | parisc*-*-linux*)
+       TARGET=PA_LINUX; TARGETDIR=pa
+       ;;
+  hppa*64-*-hpux*)
+       TARGET=PA64_HPUX; TARGETDIR=pa
+       ;;
+  hppa*-*-hpux*)
+       TARGET=PA_HPUX; TARGETDIR=pa
+       ;;
+
+  i?86-win32* | i?86-*-cygwin* | i?86-*-mingw*)
+       TARGET=X86_WIN32; TARGETDIR=x86
+       ;;
+  i?86-*-darwin*)
+       TARGET=X86_DARWIN; TARGETDIR=x86
+       ;;
+  i?86-*-solaris2.1[[0-9]]*)
+       TARGET=X86_64; TARGETDIR=x86
+       ;;
+  i?86-*-*)
+       TARGET=X86; TARGETDIR=x86
+       ;;
+
+  ia64*-*-*)
+       TARGET=IA64; TARGETDIR=ia64
+       ;;
+
+  m32r*-*-*)
+       TARGET=M32R; TARGETDIR=m32r
+       ;;
+
+  m68k-*-*)
+       TARGET=M68K; TARGETDIR=m68k
+       ;;
+
+  mips-sgi-irix5.* | mips-sgi-irix6.*)
+       TARGET=MIPS; TARGETDIR=mips
+       ;;
+  mips*-*-linux*)
+       TARGET=MIPS; TARGETDIR=mips
+       ;;
+
+  powerpc*-*-linux* | powerpc-*-sysv*)
+       TARGET=POWERPC; TARGETDIR=powerpc
+       ;;
+  powerpc-*-beos*)
+       TARGET=POWERPC; TARGETDIR=powerpc
+       ;;
+  powerpc-*-darwin*)
+       TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
+       ;;
+  powerpc-*-aix* | rs6000-*-aix*)
+       TARGET=POWERPC_AIX; TARGETDIR=powerpc
+       ;;
+  powerpc-*-freebsd*)
+       TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
+       ;;
+  powerpc*-*-rtems*)
+       TARGET=POWERPC; TARGETDIR=powerpc
+       ;;
+
+  s390-*-* | s390x-*-*)
+       TARGET=S390; TARGETDIR=s390
+       ;;
+
+  sh-*-* | sh[[34]]*-*-*)
+       TARGET=SH; TARGETDIR=sh
+       ;;
+  sh64-*-* | sh5*-*-*)
+       TARGET=SH64; TARGETDIR=sh64
+       ;;
+
+  sparc*-*-*)
+       TARGET=SPARC; TARGETDIR=sparc
+       ;;
+
+  x86_64-*-darwin*)
+       TARGET=X86_DARWIN; TARGETDIR=x86
+       ;;
+  x86_64-*-cygwin* | x86_64-*-mingw*)
+       ;;
+  x86_64-*-*)
+       TARGET=X86_64; TARGETDIR=x86
+       ;;
 esac
 
 AC_SUBST(AM_RUNTESTFLAGS)
@@ -91,11 +151,11 @@
   AC_MSG_ERROR(["libffi has not been ported to $host."])
 fi
 
-AM_CONDITIONAL(MIPS_IRIX, test x$TARGET = xMIPS_IRIX)
-AM_CONDITIONAL(MIPS_LINUX, test x$TARGET = xMIPS_LINUX)
+AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS)
 AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
 AM_CONDITIONAL(X86, test x$TARGET = xX86)
 AM_CONDITIONAL(X86_WIN32, test x$TARGET = xX86_WIN32)
+AM_CONDITIONAL(X86_DARWIN, test x$TARGET = xX86_DARWIN)
 AM_CONDITIONAL(ALPHA, test x$TARGET = xALPHA)
 AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
 AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
@@ -111,12 +171,9 @@
 AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64)
 AM_CONDITIONAL(SH, test x$TARGET = xSH)
 AM_CONDITIONAL(SH64, test x$TARGET = xSH64)
-AM_CONDITIONAL(PA, test x$TARGET = xPA)
-
-case x$TARGET in
-  xMIPS*) TARGET=MIPS ;;
-  *) ;;
-esac
+AM_CONDITIONAL(PA_LINUX, test x$TARGET = xPA_LINUX)
+AM_CONDITIONAL(PA_HPUX, test x$TARGET = xPA_HPUX)
+AM_CONDITIONAL(PA64_HPUX, test x$TARGET = xPA64_HPUX)
 
 AC_HEADER_STDC
 AC_CHECK_FUNCS(memcpy)
@@ -126,17 +183,31 @@
 AC_CHECK_SIZEOF(long double)
 
 # Also AC_SUBST this variable for ffi.h.
-HAVE_LONG_DOUBLE=0
-if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
+if test -z "$HAVE_LONG_DOUBLE"; then
+  HAVE_LONG_DOUBLE=0
+  if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then
   if test $ac_cv_sizeof_long_double != 0; then
     HAVE_LONG_DOUBLE=1
     AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type 
and it is bigger than a double])
   fi
+  fi
 fi
 AC_SUBST(HAVE_LONG_DOUBLE)
 
 AC_C_BIGENDIAN
 
+AC_CACHE_CHECK([assembler .cfi pseudo-op support],
+    libffi_cv_as_cfi_pseudo_op, [
+    libffi_cv_as_cfi_pseudo_op=unknown
+    AC_TRY_COMPILE([asm (".cfi_startproc\n\t.cfi_endproc");],,
+                  [libffi_cv_as_cfi_pseudo_op=yes],
+                  [libffi_cv_as_cfi_pseudo_op=no])
+])
+if test "x$libffi_cv_as_cfi_pseudo_op" = xyes; then
+    AC_DEFINE(HAVE_AS_CFI_PSEUDO_OP, 1,
+             [Define if your assembler supports .cfi_* directives.])
+fi
+
 if test x$TARGET = xSPARC; then
     AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs],
        libffi_cv_as_sparc_ua_pcrel, [

Index: libffi/include/Makefile.am
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/include/Makefile.am,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libffi/include/Makefile.am  3 Aug 2005 18:42:13 -0000       1.5
+++ libffi/include/Makefile.am  30 Nov 2007 20:59:54 -0000      1.6
@@ -5,11 +5,8 @@
 DISTCLEANFILES=ffitarget.h
 EXTRA_DIST=ffi.h.in ffi_common.h
 
-hackdir=$(includedir)
-
-hack_DATA= ffi.h
-
 # Where generated headers like ffitarget.h get installed.
-toollibffidir := $(includedir)
+gcc_version   := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+toollibffidir := $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
 
-toollibffi_HEADERS = ffitarget.h
+toollibffi_HEADERS = ffi.h ffitarget.h

Index: libffi/include/ffi.h.in
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/include/ffi.h.in,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/include/ffi.h.in     30 Jul 2005 19:00:13 -0000      1.4
+++ libffi/include/ffi.h.in     30 Nov 2007 20:59:55 -0000      1.5
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------*-C-*-
-   libffi @VERSION@ - Copyright (c) 1996-2003  Red Hat, Inc.
+   libffi @VERSION@ - Copyright (c) 1996-2003, 2007  Red Hat, Inc.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -82,6 +82,18 @@
 # endif
 #endif
 
+/* The closure code assumes that this works on pointers, i.e. a size_t */
+/* can hold a pointer.                                                 */
+
+typedef struct _ffi_type
+{
+  size_t size;
+  unsigned short alignment;
+  unsigned short type;
+  struct _ffi_type **elements;
+} ffi_type;
+
+#ifndef LIBFFI_HIDE_BASIC_TYPES
 #if SCHAR_MAX == 127
 # define ffi_type_uchar                ffi_type_uint8
 # define ffi_type_schar                ffi_type_sint8
@@ -112,8 +124,6 @@
  #error "int size not supported"
 #endif
 
-#define ffi_type_ulong         ffi_type_uint64
-#define ffi_type_slong         ffi_type_sint64
 #if LONG_MAX == 2147483647
 # if FFI_LONG_LONG_MAX != 9223372036854775807
   #error "no 64-bit data type supported"
@@ -122,16 +132,15 @@
  #error "long size not supported"
 #endif
 
-/* The closure code assumes that this works on pointers, i.e. a size_t */
-/* can hold a pointer.                                                 */
-
-typedef struct _ffi_type
-{
-  size_t size;
-  unsigned short alignment;
-  unsigned short type;
-  /address@hidden@*/ struct _ffi_type **elements;
-} ffi_type;
+#if LONG_MAX == 2147483647
+# define ffi_type_ulong        ffi_type_uint32
+# define ffi_type_slong        ffi_type_sint32
+#elif LONG_MAX == 9223372036854775807
+# define ffi_type_ulong        ffi_type_uint64
+# define ffi_type_slong        ffi_type_sint64
+#else
+ #error "long size not supported"
+#endif
 
 /* These are defined in types.c */
 extern ffi_type ffi_type_void;
@@ -145,9 +154,14 @@
 extern ffi_type ffi_type_sint64;
 extern ffi_type ffi_type_float;
 extern ffi_type ffi_type_double;
-extern ffi_type ffi_type_longdouble;
 extern ffi_type ffi_type_pointer;
 
+#if @HAVE_LONG_DOUBLE@
+extern ffi_type ffi_type_longdouble;
+#else
+#define ffi_type_longdouble ffi_type_double
+#endif
+#endif /* LIBFFI_HIDE_BASIC_TYPES */
 
 typedef enum {
   FFI_OK = 0,
@@ -160,8 +174,8 @@
 typedef struct {
   ffi_abi abi;
   unsigned nargs;
-  /address@hidden@*/ ffi_type **arg_types;
-  /address@hidden@*/ ffi_type *rtype;
+  ffi_type **arg_types;
+  ffi_type *rtype;
   unsigned bytes;
   unsigned flags;
 #ifdef FFI_EXTRA_CIF_FIELDS
@@ -187,10 +201,10 @@
   void*     ptr;
 } ffi_raw;
 
-void ffi_raw_call (/address@hidden@*/ ffi_cif *cif, 
+void ffi_raw_call (ffi_cif *cif,
                   void (*fn)(), 
-                  /address@hidden@*/ void *rvalue, 
-                  /address@hidden@*/ ffi_raw *avalue);
+                  void *rvalue,
+                  ffi_raw *avalue);
 
 void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
 void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
@@ -200,10 +214,10 @@
 /* packing, even on 64-bit machines.  I.e. on 64-bit machines          */
 /* longs and doubles are followed by an empty 64-bit word.             */
 
-void ffi_java_raw_call (/address@hidden@*/ ffi_cif *cif, 
+void ffi_java_raw_call (ffi_cif *cif,
                        void (*fn)(), 
-                       /address@hidden@*/ void *rvalue, 
-                       /address@hidden@*/ ffi_raw *avalue);
+                       void *rvalue,
+                       ffi_raw *avalue);
 
 void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
 void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
@@ -220,12 +234,22 @@
   void      *user_data;
 } ffi_closure __attribute__((aligned (8)));
 
+void *ffi_closure_alloc (size_t size, void **code);
+void ffi_closure_free (void *);
+
 ffi_status
 ffi_prep_closure (ffi_closure*,
                  ffi_cif *,
                  void (*fun)(ffi_cif*,void*,void**,void*),
                  void *user_data);
 
+ffi_status
+ffi_prep_closure_loc (ffi_closure*,
+                     ffi_cif *,
+                     void (*fun)(ffi_cif*,void*,void**,void*),
+                     void *user_data,
+                     void*codeloc);
+
 typedef struct {
   char tramp[FFI_TRAMPOLINE_SIZE];
 
@@ -254,25 +278,39 @@
                      void *user_data);
 
 ffi_status
+ffi_prep_raw_closure_loc (ffi_raw_closure*,
+                         ffi_cif *cif,
+                         void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                         void *user_data,
+                         void *codeloc);
+
+ffi_status
 ffi_prep_java_raw_closure (ffi_raw_closure*,
                           ffi_cif *cif,
                           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
                           void *user_data);
 
+ffi_status
+ffi_prep_java_raw_closure_loc (ffi_raw_closure*,
+                              ffi_cif *cif,
+                              void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                              void *user_data,
+                              void *codeloc);
+
 #endif /* FFI_CLOSURES */
 
 /* ---- Public interface definition -------------------------------------- */
 
-ffi_status ffi_prep_cif(/address@hidden@*/ /address@hidden@*/ ffi_cif *cif, 
+ffi_status ffi_prep_cif(ffi_cif *cif,
                        ffi_abi abi,
                        unsigned int nargs, 
-                       /address@hidden@*/ /address@hidden@*/ 
/address@hidden@*/ ffi_type *rtype, 
-                       /address@hidden@*/ ffi_type **atypes);
+                       ffi_type *rtype,
+                       ffi_type **atypes);
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
+void ffi_call(ffi_cif *cif,
              void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue);
+             void *rvalue,
+             void **avalue);
 
 /* Useful for eliminating compiler warnings */
 #define FFI_FN(f) ((void (*)())f)
@@ -310,4 +348,3 @@
 #endif
 
 #endif
-

Index: libffi/include/ffi_common.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/include/ffi_common.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/include/ffi_common.h 30 Jul 2005 19:00:13 -0000      1.3
+++ libffi/include/ffi_common.h 30 Nov 2007 20:59:55 -0000      1.4
@@ -1,5 +1,6 @@
 /* -----------------------------------------------------------------------
    ffi_common.h - Copyright (c) 1996  Red Hat, Inc.
+   Copyright (C) 2007 Free Software Foundation, Inc
 
    Common internal definitions and macros. Only necessary for building
    libffi.
@@ -18,7 +19,9 @@
    this is positioned. */
 #ifdef __GNUC__
 # define alloca __builtin_alloca
+# define MAYBE_UNUSED __attribute__((__unused__))
 #else
+# define MAYBE_UNUSED
 # if HAVE_ALLOCA_H
 #  include <alloca.h>
 # else
@@ -46,9 +49,9 @@
 #endif
 
 #ifdef FFI_DEBUG
-/address@hidden@*/ void ffi_assert(/address@hidden@*/ char *expr, 
/address@hidden@*/ char *file, int line);
+void ffi_assert(char *expr, char *file, int line);
 void ffi_stop_here(void);
-void ffi_type_test(/address@hidden@*/ /address@hidden@*/ ffi_type *a, 
/address@hidden@*/ char *file, int line);
+void ffi_type_test(ffi_type *a, char *file, int line);
 
 #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
 #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
@@ -68,9 +71,9 @@
 /* Extended cif, used in callback from assembly routine */
 typedef struct
 {
-  /address@hidden@*/ ffi_cif *cif;
-  /address@hidden@*/ void *rvalue;
-  /address@hidden@*/ void **avalue;
+  ffi_cif *cif;
+  void *rvalue;
+  void **avalue;
 } extended_cif;
 
 /* Terse sized type definitions.  */

Index: libffi/src/debug.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/debug.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/debug.c  30 Jul 2005 19:00:13 -0000      1.2
+++ libffi/src/debug.c  30 Nov 2007 20:59:55 -0000      1.3
@@ -50,10 +50,9 @@
 {
   FFI_ASSERT_AT(a != NULL, file, line);
 
-  /address@hidden@*/
   FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line);
   FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line);
   FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line);
   FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line);
-  /address@hidden@*/
+
 }

Index: libffi/src/java_raw_api.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/java_raw_api.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/java_raw_api.c   30 Jul 2005 19:00:13 -0000      1.3
+++ libffi/src/java_raw_api.c   30 Nov 2007 20:59:55 -0000      1.4
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   java_raw_api.c - Copyright (c) 1999  Red Hat, Inc.
+   java_raw_api.c - Copyright (c) 1999, 2007  Red Hat, Inc.
 
    Cloned from raw_api.c
 
@@ -285,10 +285,7 @@
  * these following couple of functions will handle the translation forth
  * and back automatically. */
 
-void ffi_java_raw_call (/address@hidden@*/ ffi_cif *cif, 
-                  void (*fn)(), 
-                  /address@hidden@*/ void *rvalue, 
-                  /address@hidden@*/ ffi_raw *raw)
+void ffi_java_raw_call (ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *raw)
 {
   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
   ffi_java_raw_to_ptrarray (cif, raw, avalue);
@@ -310,22 +307,20 @@
   ffi_java_raw_to_rvalue (cif, rvalue);
 }
 
-/* Again, here is the generic version of ffi_prep_raw_closure, which
- * will install an intermediate "hub" for translation of arguments from
- * the pointer-array format, to the raw format */
-
 ffi_status
-ffi_prep_java_raw_closure (ffi_raw_closure* cl,
+ffi_prep_java_raw_closure_loc (ffi_raw_closure* cl,
                      ffi_cif *cif,
                      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
-                     void *user_data)
+                              void *user_data,
+                              void *codeloc)
 {
   ffi_status status;
 
-  status = ffi_prep_closure ((ffi_closure*) cl, 
+  status = ffi_prep_closure_loc ((ffi_closure*) cl,
                             cif,
                             &ffi_java_translate_args,
-                            (void*)cl);
+                                codeloc,
+                                codeloc);
   if (status == FFI_OK)
     {
       cl->fun       = fun;
@@ -335,6 +330,19 @@
   return status;
 }
 
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_java_raw_closure (ffi_raw_closure* cl,
+                          ffi_cif *cif,
+                          void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                          void *user_data)
+{
+  return ffi_prep_java_raw_closure_loc (cl, cif, fun, user_data, cl);
+}
+
 #endif /* FFI_CLOSURES */
 #endif /* !FFI_NATIVE_RAW_API */
 #endif /* !FFI_NO_RAW_API */

Index: libffi/src/prep_cif.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/prep_cif.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/src/prep_cif.c       30 Jul 2005 19:00:13 -0000      1.4
+++ libffi/src/prep_cif.c       30 Nov 2007 20:59:55 -0000      1.5
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   prep_cif.c - Copyright (c) 1996, 1998  Red Hat, Inc.
+   prep_cif.c - Copyright (c) 1996, 1998, 2007  Red Hat, Inc.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -25,7 +25,6 @@
 #include <ffi_common.h>
 #include <stdlib.h>
 
-
 /* Round up to FFI_SIZEOF_ARG. */
 
 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
@@ -33,14 +32,12 @@
 /* Perform machine independent initialization of aggregate type
    specifications. */
 
-static ffi_status initialize_aggregate(/address@hidden@*/ ffi_type *arg)
+static ffi_status initialize_aggregate(ffi_type *arg)
 {
   ffi_type **ptr; 
 
   FFI_ASSERT(arg != NULL);
 
-  /address@hidden@*/
-
   FFI_ASSERT(arg->elements != NULL);
   FFI_ASSERT(arg->size == 0);
   FFI_ASSERT(arg->alignment == 0);
@@ -77,8 +74,6 @@
     return FFI_BAD_TYPEDEF;
   else
     return FFI_OK;
-
-  /address@hidden@*/
 }
 
 #ifndef __CRIS__
@@ -89,10 +84,8 @@
 /* Perform machine independent ffi_cif preparation, then call
    machine dependent routine. */
 
-ffi_status ffi_prep_cif(/address@hidden@*/ /address@hidden@*/ ffi_cif *cif, 
-                       ffi_abi abi, unsigned int nargs, 
-                       /address@hidden@*/ /address@hidden@*/ 
/address@hidden@*/ ffi_type *rtype, 
-                       /address@hidden@*/ ffi_type **atypes)
+ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
+                       ffi_type *rtype, ffi_type **atypes)
 {
   unsigned bytes = 0;
   unsigned int i;
@@ -109,10 +102,8 @@
   cif->flags = 0;
 
   /* Initialize the return type if necessary */
-  /address@hidden@*/
   if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
     return FFI_BAD_TYPEDEF;
-  /address@hidden@*/
 
   /* Perform a sanity check on the return type */
   FFI_ASSERT_VALID_TYPE(cif->rtype);
@@ -124,6 +115,9 @@
 #ifdef SPARC
       && (cif->abi != FFI_V9 || cif->rtype->size > 32)
 #endif
+#ifdef X86_DARWIN
+      && (cif->rtype->size > 8)
+#endif
       )
     bytes = STACK_ARG_SIZE(sizeof(void*));
 #endif
@@ -164,3 +158,16 @@
   return ffi_prep_cif_machdep(cif);
 }
 #endif /* not __CRIS__ */
+
+#if FFI_CLOSURES
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+                 ffi_cif* cif,
+                 void (*fun)(ffi_cif*,void*,void**,void*),
+                 void *user_data)
+{
+  return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
+}
+
+#endif

Index: libffi/src/raw_api.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/raw_api.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/raw_api.c        30 Jul 2005 19:00:13 -0000      1.2
+++ libffi/src/raw_api.c        30 Nov 2007 20:59:55 -0000      1.3
@@ -189,10 +189,7 @@
  * these following couple of functions will handle the translation forth
  * and back automatically. */
 
-void ffi_raw_call (/address@hidden@*/ ffi_cif *cif, 
-                  void (*fn)(), 
-                  /address@hidden@*/ void *rvalue, 
-                  /address@hidden@*/ ffi_raw *raw)
+void ffi_raw_call (ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *raw)
 {
   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
   ffi_raw_to_ptrarray (cif, raw, avalue);
@@ -212,22 +209,20 @@
   (*cl->fun) (cif, rvalue, raw, cl->user_data);
 }
 
-/* Again, here is the generic version of ffi_prep_raw_closure, which
- * will install an intermediate "hub" for translation of arguments from
- * the pointer-array format, to the raw format */
-
 ffi_status
-ffi_prep_raw_closure (ffi_raw_closure* cl,
+ffi_prep_raw_closure_loc (ffi_raw_closure* cl,
                      ffi_cif *cif,
                      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
-                     void *user_data)
+                         void *user_data,
+                         void *codeloc)
 {
   ffi_status status;
 
-  status = ffi_prep_closure ((ffi_closure*) cl, 
+  status = ffi_prep_closure_loc ((ffi_closure*) cl,
                             cif,
                             &ffi_translate_args,
-                            (void*)cl);
+                                codeloc,
+                                codeloc);
   if (status == FFI_OK)
     {
       cl->fun       = fun;
@@ -239,4 +234,22 @@
 
 #endif /* FFI_CLOSURES */
 #endif /* !FFI_NATIVE_RAW_API */
+
+#if FFI_CLOSURES
+
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure* cl,
+                     ffi_cif *cif,
+                     void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                     void *user_data)
+{
+  return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl);
+}
+
+#endif /* FFI_CLOSURES */
+
 #endif /* !FFI_NO_RAW_API */

Index: libffi/src/types.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/types.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libffi/src/types.c  30 Jul 2005 19:00:13 -0000      1.5
+++ libffi/src/types.c  30 Nov 2007 20:59:55 -0000      1.6
@@ -23,6 +23,10 @@
    OTHER DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
+/* Hide the basic type definitions from the header file, so that we
+   can redefine them here as "const".  */
+#define LIBFFI_HIDE_BASIC_TYPES
+
 #include <ffi.h>
 #include <ffi_common.h>
 
@@ -33,14 +37,14 @@
   char c;                                      \
   type x;                                      \
 };                                             \
-ffi_type ffi_type_##name = {                   \
+const ffi_type ffi_type_##name = {             \
   sizeof(type),                                        \
   offsetof(struct struct_align_##name, x),     \
   id, NULL                                     \
 }
 
 /* Size and alignment are fake here. They must not be 0. */
-ffi_type ffi_type_void = {
+const ffi_type ffi_type_void = {
   1, 1, FFI_TYPE_VOID, NULL
 };
 
@@ -57,4 +61,16 @@
 
 FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
 FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
+
+#ifdef __alpha__
+/* Even if we're not configured to default to 128-bit long double, 
+   maintain binary compatibility, as -mlong-double-128 can be used
+   at any time.  */
+/* Validate the hard-coded number below.  */
+# if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4
+#  error FFI_TYPE_LONGDOUBLE out of date
+# endif
+const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
+#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
+#endif

Index: libffi/src/alpha/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/alpha/ffi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/alpha/ffi.c      30 Jul 2005 19:00:13 -0000      1.2
+++ libffi/src/alpha/ffi.c      30 Nov 2007 20:59:55 -0000      1.3
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc.
+   ffi.c - Copyright (c) 1998, 2001, 2007 Red Hat, Inc.
    
    Alpha Foreign Function Interface 
 
@@ -25,11 +25,22 @@
 
 #include <ffi.h>
 #include <ffi_common.h>
-
 #include <stdlib.h>
 
-extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
-extern void ffi_closure_osf(void);
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+   all further uses in this file will refer to the 128-bit type.  */
+#if defined(__LONG_DOUBLE_128__)
+# if FFI_TYPE_LONGDOUBLE != 4
+#  error FFI_TYPE_LONGDOUBLE out of date
+# endif
+#else
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
+#endif
+
+extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)())
+  FFI_HIDDEN;
+extern void ffi_closure_osf(void) FFI_HIDDEN;
 
 
 ffi_status
@@ -49,6 +60,11 @@
       cif->flags = cif->rtype->type;
       break;
 
+    case FFI_TYPE_LONGDOUBLE:
+      /* 128-bit long double is returned in memory, like a struct.  */
+      cif->flags = FFI_TYPE_STRUCT;
+      break;
+
     default:
       cif->flags = FFI_TYPE_INT;
       break;
@@ -57,6 +73,7 @@
   return FFI_OK;
 }
 
+
 void
 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
@@ -64,8 +81,6 @@
   long i, avn;
   ffi_type **arg_types;
   
-  FFI_ASSERT (cif->abi == FFI_OSF);
-
   /* 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->flags == FFI_TYPE_STRUCT)
@@ -84,6 +99,8 @@
 
   while (i < avn)
     {
+      size_t size = (*arg_types)->size;
+
       switch ((*arg_types)->type)
        {
        case FFI_TYPE_SINT8:
@@ -129,6 +146,12 @@
          *(double *) argp = *(double *)(* avalue);
          break;
 
+       case FFI_TYPE_LONGDOUBLE:
+         /* 128-bit long double is passed by reference.  */
+         *(long double **) argp = (long double *)(* avalue);
+         size = sizeof (long double *);
+         break;
+
        case FFI_TYPE_STRUCT:
          memcpy(argp, *avalue, (*arg_types)->size);
          break;
@@ -137,7 +160,7 @@
          FFI_ASSERT(0);
        }
 
-      argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
       i++, arg_types++, avalue++;
     }
 
@@ -146,15 +169,14 @@
 
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp;
 
-  FFI_ASSERT (cif->abi == FFI_OSF);
-
   tramp = (unsigned int *) &closure->tramp[0];
   tramp[0] = 0x47fb0401;       /* mov $27,$1           */
   tramp[1] = 0xa77b0010;       /* ldq $27,16($27)      */
@@ -177,7 +199,8 @@
   return FFI_OK;
 }
 
-int
+
+long FFI_HIDDEN
 ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
 {
   ffi_cif *cif;
@@ -205,6 +228,8 @@
   /* Grab the addresses of the arguments from the stack frame.  */
   while (i < avn)
     {
+      size_t size = arg_types[i]->size;
+
       switch (arg_types[i]->type)
        {
        case FFI_TYPE_SINT8:
@@ -236,16 +261,22 @@
          avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
          break;
 
+       case FFI_TYPE_LONGDOUBLE:
+         /* 128-bit long double is passed by reference.  */
+         avalue[i] = (long double *) argp[argn];
+         size = sizeof (long double *);
+         break;
+
        default:
-         FFI_ASSERT(0);
+         abort ();
        }
 
-      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+      argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
       i++;
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  closure->fun (cif, rvalue, avalue, closure->user_data);
 
   /* Tell ffi_closure_osf how to perform return type promotions.  */
   return cif->rtype->type;

Index: libffi/src/alpha/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/alpha/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/alpha/ffitarget.h        30 Jul 2005 19:00:13 -0000      1.1
+++ libffi/src/alpha/ffitarget.h        30 Nov 2007 20:59:55 -0000      1.2
@@ -33,8 +33,8 @@
 typedef enum ffi_abi {
   FFI_FIRST_ABI = 0,
   FFI_OSF,
-  FFI_DEFAULT_ABI = FFI_OSF,
-  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+  FFI_LAST_ABI,
+  FFI_DEFAULT_ABI = FFI_OSF
 } ffi_abi;
 #endif
 
@@ -45,4 +45,3 @@
 #define FFI_NATIVE_RAW_API 0
 
 #endif
-

Index: libffi/src/alpha/osf.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/alpha/osf.S,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/alpha/osf.S      30 Jul 2005 19:00:13 -0000      1.3
+++ libffi/src/alpha/osf.S      30 Nov 2007 20:59:55 -0000      1.4
@@ -1,10 +1,8 @@
 /* -----------------------------------------------------------------------
-   osf.S - Copyright (c) 1998, 2001 Red Hat
+   osf.S - Copyright (c) 1998, 2001, 2007 Red Hat
    
    Alpha/OSF Foreign Function Interface 
 
-   $Id: osf.S,v 1.3 2005/07/30 19:00:13 ktreichel Exp $
-
    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
@@ -42,6 +40,8 @@
        .align  3
        .globl  ffi_call_osf
        .ent    ffi_call_osf
+       FFI_HIDDEN(ffi_call_osf)
+
 ffi_call_osf:
        .frame  $15, 32, $26, 0
        .mask   0x4008000, -32
@@ -129,6 +129,8 @@
        .align  3
        .globl  ffi_closure_osf
        .ent    ffi_closure_osf
+       FFI_HIDDEN(ffi_closure_osf)
+
 ffi_closure_osf:
        .frame  $30, 16*8, $26, 0
        .mask   0x4000000, -16*8
@@ -265,7 +267,7 @@
        .gprel32 $load_32       # FFI_TYPE_INT
        .gprel32 $load_float    # FFI_TYPE_FLOAT
        .gprel32 $load_double   # FFI_TYPE_DOUBLE
-       .gprel32 $load_double   # FFI_TYPE_LONGDOUBLE
+       .gprel32 $load_none     # FFI_TYPE_LONGDOUBLE
        .gprel32 $load_u8       # FFI_TYPE_UINT8
        .gprel32 $load_s8       # FFI_TYPE_SINT8
        .gprel32 $load_u16      # FFI_TYPE_UINT16

Index: libffi/src/arm/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/arm/ffi.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/arm/ffi.c        30 Jul 2005 19:00:14 -0000      1.3
+++ libffi/src/arm/ffi.c        30 Nov 2007 20:59:55 -0000      1.4
@@ -31,9 +31,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-/address@hidden@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/address@hidden@*/
 {
   register unsigned int i;
   register void **p_argv;
@@ -42,7 +40,7 @@
 
   argp = stack;
 
-  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
+  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
     *(void **) argp = ecif->rvalue;
     argp += 4;
   }
@@ -60,6 +58,9 @@
        argp = (char *) ALIGN(argp, (*p_arg)->alignment);
       }
 
+      if ((*p_arg)->type == FFI_TYPE_STRUCT)
+       argp = (char *) ALIGN(argp, 4);
+
          z = (*p_arg)->size;
          if (z < sizeof(int))
            {
@@ -83,7 +84,7 @@
                  break;
                  
                case FFI_TYPE_STRUCT:
-                 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+                 memcpy(argp, *p_argv, (*p_arg)->size);
                  break;
 
                default:
@@ -117,7 +118,6 @@
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
-    case FFI_TYPE_STRUCT:
     case FFI_TYPE_FLOAT:
     case FFI_TYPE_DOUBLE:
       cif->flags = (unsigned) cif->rtype->type;
@@ -128,6 +128,17 @@
       cif->flags = (unsigned) FFI_TYPE_SINT64;
       break;
 
+    case FFI_TYPE_STRUCT:
+      if (cif->rtype->size <= 4)
+       /* A Composite Type not larger than 4 bytes is returned in r0.  */
+       cif->flags = (unsigned)FFI_TYPE_INT;
+      else
+       /* A Composite Type larger than 4 bytes, or whose size cannot
+          be determined statically ... is stored in memory at an
+          address passed [in r0].  */
+       cif->flags = (unsigned)FFI_TYPE_STRUCT;
+      break;
+
     default:
       cif->flags = FFI_TYPE_INT;
       break;
@@ -136,50 +147,162 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /address@hidden@*/ extended_cif *, 
-                         unsigned, unsigned, 
-                         /address@hidden@*/ unsigned *, 
-                         void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)());
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue)
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
+  int small_struct = (cif->flags == FFI_TYPE_INT 
+                     && cif->rtype->type == FFI_TYPE_STRUCT);
+
   ecif.cif = cif;
   ecif.avalue = avalue;
   
+  unsigned int temp;
+  
   /* 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))
+      (cif->flags == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
+  else if (small_struct)
+    ecif.rvalue = &temp;
   else
     ecif.rvalue = rvalue;
     
-  
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                   fn);
+
       break;
     default:
       FFI_ASSERT(0);
       break;
     }
+  if (small_struct)
+    memcpy (rvalue, &temp, cif->rtype->size);
+}
+
+/** private members **/
+
+static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
+                                        void** args, ffi_cif* cif);
+
+void ffi_closure_SYSV (ffi_closure *);
+
+/* This function is jumped to by the trampoline */
+
+unsigned int
+ffi_closure_SYSV_inner (closure, respp, args)
+     ffi_closure *closure;
+     void **respp;
+     void *args;
+{
+  // our various things...
+  ffi_cif       *cif;
+  void         **arg_area;
+
+  cif         = closure->cif;
+  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
+
+  /* this call will initialize ARG_AREA, such that each
+   * element in that array points to the corresponding 
+   * value on the stack; and if the function returns
+   * a structure, it will re-set RESP to point to the
+   * structure return address.  */
+
+  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
+
+  (closure->fun) (cif, *respp, arg_area, closure->user_data);
+
+  return cif->flags;
+}
+
+/address@hidden@*/
+static void 
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+                           void **avalue, ffi_cif *cif)
+/address@hidden@*/
+{
+  register unsigned int i;
+  register void **p_argv;
+  register char *argp;
+  register ffi_type **p_arg;
+
+  argp = stack;
+
+  if ( cif->flags == FFI_TYPE_STRUCT ) {
+    *rvalue = *(void **) argp;
+    argp += 4;
+  }
+
+  p_argv = avalue;
+
+  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+    {
+      size_t z;
+
+      size_t alignment = (*p_arg)->alignment;
+      if (alignment < 4)
+       alignment = 4;
+      /* Align if necessary */
+      if ((alignment - 1) & (unsigned) argp) {
+       argp = (char *) ALIGN(argp, alignment);
+      }
+
+      z = (*p_arg)->size;
+
+      /* because we're little endian, this is what it turns into.   */
+
+      *p_argv = (void*) argp;
+
+      p_argv++;
+      argp += z;
+    }
+  
+  return;
+}
+
+/* How to make a trampoline.  */
+
+#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                             \
+({ unsigned char *__tramp = (unsigned char*)(TRAMP);                   \
+   unsigned int  __fun = (unsigned int)(FUN);                          \
+   unsigned int  __ctx = (unsigned int)(CTX);                          \
+   *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \
+   *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */       \
+   *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */       \
+   *(unsigned int*) &__tramp[12] = __ctx;                              \
+   *(unsigned int*) &__tramp[16] = __fun;                              \
+   __clear_cache((&__tramp[0]), (&__tramp[19]));                       \
+ })
+
+
+/* the cif must already be prep'ed */
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+                     ffi_cif* cif,
+                     void (*fun)(ffi_cif*,void*,void**,void*),
+                     void *user_data,
+                     void *codeloc)
+{
+  FFI_ASSERT (cif->abi == FFI_SYSV);
+
+  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
+                      &ffi_closure_SYSV,  \
+                      codeloc);
+    
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
 }

Index: libffi/src/arm/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/arm/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/arm/ffitarget.h  30 Jul 2005 19:00:14 -0000      1.1
+++ libffi/src/arm/ffitarget.h  30 Nov 2007 20:59:56 -0000      1.2
@@ -40,7 +40,8 @@
 
 /* ---- Definitions for closures ----------------------------------------- */
 
-#define FFI_CLOSURES 0
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 20
 #define FFI_NATIVE_RAW_API 0
 
 #endif

Index: libffi/src/arm/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/arm/sysv.S,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/arm/sysv.S       30 Jul 2005 19:00:14 -0000      1.3
+++ libffi/src/arm/sysv.S       30 Nov 2007 20:59:56 -0000      1.4
@@ -82,6 +82,14 @@
 # define call_reg(x)   mov     lr, pc ; mov    pc, x
 #endif
 
+/* Conditionally compile unwinder directives.  */
+#ifdef __ARM_EABI__
+#define UNWIND
+#else
+#define UNWIND @
+#endif 
+
+       
 #if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
 .macro ARM_FUNC_START name
        .text
@@ -92,6 +100,7 @@
        bx      pc
        nop
        .arm
+       UNWIND .fnstart
 /* A hook to tell gdb that we've switched to ARM mode.  Also used to call
    directly from other local arm routines.  */
 _L__\name:             
@@ -102,6 +111,7 @@
        .align 0
        .arm
        ENTRY(\name)
+       UNWIND .fnstart
 .endm
 #endif
 
@@ -134,8 +144,11 @@
 ARM_FUNC_START ffi_call_SYSV
        @ Save registers
         stmfd  sp!, {r0-r3, fp, lr}
+       UNWIND .save    {r0-r3, fp, lr}
        mov     fp, sp
 
+       UNWIND .setfp   fp, sp
+
        @ Make room for all of the new args.
        sub     sp, fp, r2
 
@@ -205,5 +218,78 @@
        RETLDM  "r0-r3,fp"
 
 .ffi_call_SYSV_end:
+       UNWIND .fnend
         .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
 
+/*
+       unsigned int FFI_HIDDEN
+       ffi_closure_SYSV_inner (closure, respp, args)
+            ffi_closure *closure;
+            void **respp;
+            void *args;
+*/
+
+ARM_FUNC_START ffi_closure_SYSV
+       UNWIND .pad #16
+       add     ip, sp, #16
+       stmfd   sp!, {ip, lr}
+       UNWIND .save    {r0, lr}
+       add     r2, sp, #8
+       .pad #16
+       sub     sp, sp, #16
+       str     sp, [sp, #8]
+       add     r1, sp, #8
+       bl      ffi_closure_SYSV_inner
+       cmp     r0, #FFI_TYPE_INT
+       beq     .Lretint
+
+       cmp     r0, #FFI_TYPE_FLOAT
+#ifdef __SOFTFP__
+       beq     .Lretint
+#else
+       beq     .Lretfloat
+#endif
+
+       cmp     r0, #FFI_TYPE_DOUBLE
+#ifdef __SOFTFP__
+       beq     .Lretlonglong
+#else
+       beq     .Lretdouble
+#endif
+
+       cmp     r0, #FFI_TYPE_LONGDOUBLE
+#ifdef __SOFTFP__
+       beq     .Lretlonglong
+#else
+       beq     .Lretlongdouble
+#endif
+
+       cmp     r0, #FFI_TYPE_SINT64
+       beq     .Lretlonglong
+.Lclosure_epilogue:
+       add     sp, sp, #16
+       ldmfd   sp, {sp, pc}
+.Lretint:
+       ldr     r0, [sp]
+       b       .Lclosure_epilogue
+.Lretlonglong:
+       ldr     r0, [sp]
+       ldr     r1, [sp, #4]
+       b       .Lclosure_epilogue
+
+#ifndef __SOFTFP__
+.Lretfloat:
+       ldfs    f0, [sp]
+       b       .Lclosure_epilogue
+.Lretdouble:
+       ldfd    f0, [sp]
+       b       .Lclosure_epilogue
+.Lretlongdouble:
+       ldfd    f0, [sp]
+       b       .Lclosure_epilogue
+#endif
+
+.ffi_closure_SYSV_end:
+       UNWIND .fnend
+        .size    
CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+

Index: libffi/src/cris/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/cris/ffi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/cris/ffi.c       30 Jul 2005 19:00:14 -0000      1.2
+++ libffi/src/cris/ffi.c       30 Nov 2007 20:59:56 -0000      1.3
@@ -2,6 +2,7 @@
    ffi.c - Copyright (c) 1998 Cygnus Solutions
            Copyright (c) 2004 Simon Posnjak
           Copyright (c) 2005 Axis Communications AB
+          Copyright (C) 2007 Free Software Foundation, Inc.
 
    CRIS Foreign Function Interface
 
@@ -360,10 +361,11 @@
 /* API function: Prepare the trampoline.  */
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif *, void *, void **, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   void *innerfn = ffi_prep_closure_inner;
   FFI_ASSERT (cif->abi == FFI_SYSV);
@@ -375,7 +377,7 @@
   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
          &innerfn, sizeof (void *));
   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
-         &closure, sizeof (void *));
+         &codeloc, sizeof (void *));
 
   return FFI_OK;
 }

Index: libffi/src/frv/eabi.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/frv/eabi.S,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/frv/eabi.S       30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/frv/eabi.S       30 Nov 2007 20:59:56 -0000      1.2
@@ -3,8 +3,6 @@
    
    FR-V Assembly glue.
 
-   $Id: eabi.S,v 1.1 2005/07/30 19:00:15 ktreichel Exp $
-
    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

Index: libffi/src/frv/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/frv/ffi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/frv/ffi.c        30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/frv/ffi.c        30 Nov 2007 20:59:56 -0000      1.2
@@ -1,5 +1,6 @@
 /* -----------------------------------------------------------------------
    ffi.c - Copyright (c) 2004  Anthony Green
+   Copyright (C) 2007  Free Software Foundation, Inc.
    
    FR-V Foreign Function Interface 
 
@@ -243,14 +244,15 @@
 }
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
   unsigned long fn = (long) ffi_closure_eabi;
-  unsigned long cls = (long) closure;
+  unsigned long cls = (long) codeloc;
 #ifdef __FRV_FDPIC__
   register void *got __asm__("gr15");
 #endif
@@ -259,7 +261,7 @@
   fn = (unsigned long) ffi_closure_eabi;
 
 #ifdef __FRV_FDPIC__
-  tramp[0] = &tramp[2];
+  tramp[0] = &((unsigned int *)codeloc)[2];
   tramp[1] = got;
   tramp[2] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
   tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
@@ -281,7 +283,8 @@
 
   /* Cache flushing.  */
   for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
-    __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i));
+    __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
+                     "r" (codeloc));
 
   return FFI_OK;
 }

Index: libffi/src/ia64/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/ia64/ffi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/ia64/ffi.c       30 Jul 2005 19:00:14 -0000      1.2
+++ libffi/src/ia64/ffi.c       30 Nov 2007 20:59:56 -0000      1.3
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1998 Red Hat, Inc.
+   ffi.c - Copyright (c) 1998, 2007 Red Hat, Inc.
           Copyright (c) 2000 Hewlett Packard Company
    
    IA64 Foreign Function Interface 
@@ -69,24 +69,19 @@
 #endif
 }
 
-/* Store VALUE to ADDR in the current cpu implementation's fp spill format.  */
+/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
+   This is a macro instead of a function, so that it works for all 3 floating
+   point types without type conversions.  Type conversion to long double breaks
+   the denorm support.  */
 
-static inline void
-stf_spill(fpreg *addr, __float80 value)
-{
+#define stf_spill(addr, value) \
   asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
-}
 
 /* Load a value from ADDR, which is in the current cpu implementation's
-   fp spill format.  */
+   fp spill format.  As above, this must also be a macro.  */
 
-static inline __float80
-ldf_fill(fpreg *addr)
-{
-  __float80 ret;
-  asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr));
-  return ret;
-}
+#define ldf_fill(result, addr) \
+  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
 
 /* Return the size of the C type associated with with TYPE.  Which will
    be one of the FFI_IA64_TYPE_HFA_* values.  */
@@ -110,17 +105,20 @@
 /* Load from ADDR a value indicated by TYPE.  Which will be one of
    the FFI_IA64_TYPE_HFA_* values.  */
 
-static __float80
-hfa_type_load (int type, void *addr)
+static void
+hfa_type_load (fpreg *fpaddr, int type, void *addr)
 {
   switch (type)
     {
     case FFI_IA64_TYPE_HFA_FLOAT:
-      return *(float *) addr;
+      stf_spill (fpaddr, *(float *) addr);
+      return;
     case FFI_IA64_TYPE_HFA_DOUBLE:
-      return *(double *) addr;
+      stf_spill (fpaddr, *(double *) addr);
+      return;
     case FFI_IA64_TYPE_HFA_LDOUBLE:
-      return *(__float80 *) addr;
+      stf_spill (fpaddr, *(__float80 *) addr);
+      return;
     default:
       abort ();
     }
@@ -130,19 +128,31 @@
    the FFI_IA64_TYPE_HFA_* values.  */
 
 static void
-hfa_type_store (int type, void *addr, __float80 value)
+hfa_type_store (int type, void *addr, fpreg *fpaddr)
 {
   switch (type)
     {
     case FFI_IA64_TYPE_HFA_FLOAT:
-      *(float *) addr = value;
+      {
+       float result;
+       ldf_fill (result, fpaddr);
+       *(float *) addr = result;
       break;
+      }
     case FFI_IA64_TYPE_HFA_DOUBLE:
-      *(double *) addr = value;
+      {
+       double result;
+       ldf_fill (result, fpaddr);
+       *(double *) addr = result;
       break;
+      }
     case FFI_IA64_TYPE_HFA_LDOUBLE:
-      *(__float80 *) addr = value;
+      {
+       __float80 result;
+       ldf_fill (result, fpaddr);
+       *(__float80 *) addr = result;
       break;
+      }
     default:
       abort ();
     }
@@ -351,8 +361,8 @@
                       && offset < size
                       && gp_offset < 8 * 8)
                  {
-                   stf_spill (&stack->fp_regs[fpcount],
-                              hfa_type_load (hfa_type, avalue[i] + offset));
+                   hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
+                                  avalue[i] + offset);
                    offset += hfa_size;
                    gp_offset += hfa_size;
                    fpcount += 1;
@@ -390,10 +400,11 @@
 extern void ffi_closure_unix ();
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*,void*,void**,void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   /* The layout of a function descriptor.  A C function pointer really 
      points to one of these.  */
@@ -420,7 +431,7 @@
 
   tramp->code_pointer = fd->code_pointer;
   tramp->real_gp = fd->gp;
-  tramp->fake_gp = (UINT64)(PTR64)closure;
+  tramp->fake_gp = (UINT64)(PTR64)codeloc;
   closure->cif = cif;
   closure->user_data = user_data;
   closure->fun = fun;
@@ -475,9 +486,11 @@
        case FFI_TYPE_FLOAT:
          if (gpcount < 8 && fpcount < 8)
            {
-             void *addr = &stack->fp_regs[fpcount++];
+             fpreg *addr = &stack->fp_regs[fpcount++];
+             float result;
              avalue[i] = addr;
-             *(float *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(float *)addr = result;
            }
          else
            avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
@@ -487,9 +500,11 @@
        case FFI_TYPE_DOUBLE:
          if (gpcount < 8 && fpcount < 8)
            {
-             void *addr = &stack->fp_regs[fpcount++];
+             fpreg *addr = &stack->fp_regs[fpcount++];
+             double result;
              avalue[i] = addr;
-             *(double *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(double *)addr = result;
            }
          else
            avalue[i] = &stack->gp_regs[gpcount];
@@ -501,9 +516,11 @@
            gpcount++;
          if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
            {
-             void *addr = &stack->fp_regs[fpcount++];
+             fpreg *addr = &stack->fp_regs[fpcount++];
+             __float80 result;
              avalue[i] = addr;
-             *(__float80 *)addr = ldf_fill (addr);
+             ldf_fill (result, addr);
+             *(__float80 *)addr = result;
            }
          else
            avalue[i] = &stack->gp_regs[gpcount];
@@ -534,7 +551,7 @@
                       && gp_offset < 8 * 8)
                  {
                    hfa_type_store (hfa_type, addr + offset, 
-                                   ldf_fill (&stack->fp_regs[fpcount]));
+                                   &stack->fp_regs[fpcount]);
                    offset += hfa_size;
                    gp_offset += hfa_size;
                    fpcount += 1;

Index: libffi/src/m32r/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/m32r/ffi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/m32r/ffi.c       30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/m32r/ffi.c       30 Nov 2007 20:59:56 -0000      1.2
@@ -31,9 +31,7 @@
 /* ffi_prep_args is called by the assembly routine once stack
    space has been allocated for the function's arguments.  */
 
-/address@hidden@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/address@hidden@*/
 {
   unsigned int i;
   int tmp;
@@ -173,20 +171,10 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /address@hidden@*/ extended_cif *, 
-                         unsigned, unsigned, 
-                         /address@hidden@*/ unsigned *, 
-                         void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
-
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue)
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)());
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -198,9 +186,7 @@
   if ((rvalue == NULL) && 
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca (cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;    
@@ -208,7 +194,6 @@
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
                    cif->flags, ecif.rvalue, fn);
       if (cif->rtype->type == FFI_TYPE_STRUCT)
@@ -237,7 +222,6 @@
                }
            }
        }
-      /address@hidden@*/
       break;
 
     default:

Index: libffi/src/m68k/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/m68k/ffi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/m68k/ffi.c       6 Feb 2003 01:15:38 -0000       1.2
+++ libffi/src/m68k/ffi.c       30 Nov 2007 20:59:56 -0000      1.3
@@ -8,11 +8,23 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <asm/cachectl.h>
+
+void ffi_call_SYSV (extended_cif *,
+                   unsigned, unsigned,
+                   void *, void (*fn) ());
+void *ffi_prep_args (void *stack, extended_cif *ecif);
+void ffi_closure_SYSV (ffi_closure *);
+void ffi_closure_struct_SYSV (ffi_closure *);
+unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
+                                    void *resp, void *args);
 
 /* ffi_prep_args is called by the assembly routine once stack space has
    been allocated for the function's arguments.  */
 
-static void *
+void *
 ffi_prep_args (void *stack, extended_cif *ecif)
 {
   unsigned int i;
@@ -24,7 +36,7 @@
   argp = stack;
 
   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
-      && ecif->cif->rtype->size > 8)
+      && !ecif->cif->flags)
     struct_value_ptr = ecif->rvalue;
   else
     struct_value_ptr = NULL;
@@ -37,10 +49,6 @@
     {
       size_t z;
 
-      /* Align if necessary.  */
-      if (((*p_arg)->alignment - 1) & (unsigned) argp)
-       argp = (char *) ALIGN (argp, (*p_arg)->alignment);
-
          z = (*p_arg)->size;
          if (z < sizeof (int))
            {
@@ -72,7 +80,14 @@
              z = sizeof (int);
            }
          else
+       {
            memcpy (argp, *p_argv, z);
+
+         /* Align if necessary.  */
+         if ((sizeof(int) - 1) & z)
+           z = ALIGN(z, sizeof(int));
+       }
+
          p_argv++;
          argp += z;
     }
@@ -86,7 +101,8 @@
 #define CIF_FLAGS_DOUBLE       8
 #define CIF_FLAGS_LDOUBLE      16
 #define CIF_FLAGS_POINTER      32
-#define CIF_FLAGS_STRUCT       64
+#define CIF_FLAGS_STRUCT1      64
+#define CIF_FLAGS_STRUCT2      128
 
 /* Perform machine dependent cif processing */
 ffi_status
@@ -100,13 +116,25 @@
       break;
 
     case FFI_TYPE_STRUCT:
-      if (cif->rtype->size > 4 && cif->rtype->size <= 8)
+      switch (cif->rtype->size)
+       {
+       case 1:
+         cif->flags = CIF_FLAGS_STRUCT1;
+         break;
+       case 2:
+         cif->flags = CIF_FLAGS_STRUCT2;
+         break;
+       case 4:
+         cif->flags = CIF_FLAGS_INT;
+         break;
+       case 8:
        cif->flags = CIF_FLAGS_DINT;
-      else if (cif->rtype->size <= 4)
-       cif->flags = CIF_FLAGS_STRUCT;
-      else
+         break;
+       default:
        cif->flags = 0;
       break;
+       }
+      break;
 
     case FFI_TYPE_FLOAT:
       cif->flags = CIF_FLAGS_FLOAT;
@@ -137,11 +165,6 @@
   return FFI_OK;
 }
 
-extern void ffi_call_SYSV (void *(*) (void *, extended_cif *), 
-                          extended_cif *, 
-                          unsigned, unsigned, unsigned,
-                          void *, void (*fn) ());
-
 void
 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
 {
@@ -160,12 +183,10 @@
   else
     ecif.rvalue = rvalue;
     
-  
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, 
-                    cif->flags, cif->rtype->size * 8,
+      ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
                     ecif.rvalue, fn);
       break;
 
@@ -174,3 +195,84 @@
       break;
     }
 }
+
+static void
+ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
+{
+  unsigned int i;
+  void **p_argv;
+  char *argp;
+  ffi_type **p_arg;
+
+  argp = stack;
+  p_argv = avalue;
+
+  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+    {
+      size_t z;
+
+      z = (*p_arg)->size;
+      if (z <= 4)
+       {
+         *p_argv = (void *) (argp + 4 - z);
+
+         z = 4;
+       }
+      else
+       {
+         *p_argv = (void *) argp;
+
+         /* Align if necessary */
+         if ((sizeof(int) - 1) & z)
+           z = ALIGN(z, sizeof(int));
+       }
+
+      p_argv++;
+      argp += z;
+    }
+}
+
+unsigned int
+ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
+{
+  ffi_cif *cif;
+  void **arg_area;
+
+  cif = closure->cif;
+  arg_area = (void**) alloca (cif->nargs * sizeof (void *));
+
+  ffi_prep_incoming_args_SYSV(args, arg_area, cif);
+
+  (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+  return cif->flags;
+}
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+                     ffi_cif* cif,
+                     void (*fun)(ffi_cif*,void*,void**,void*),
+                     void *user_data,
+                     void *codeloc)
+{
+  FFI_ASSERT (cif->abi == FFI_SYSV);
+
+  *(unsigned short *)closure->tramp = 0x207c;
+  *(void **)(closure->tramp + 2) = codeloc;
+  *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
+  if (cif->rtype->type == FFI_TYPE_STRUCT
+      && !cif->flags)
+    *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
+  else
+    *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
+
+  syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
+         FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
+
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+

Index: libffi/src/m68k/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/m68k/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/m68k/ffitarget.h 30 Jul 2005 19:00:14 -0000      1.1
+++ libffi/src/m68k/ffitarget.h 30 Nov 2007 20:59:56 -0000      1.2
@@ -40,7 +40,8 @@
 
 /* ---- Definitions for closures ----------------------------------------- */
 
-#define FFI_CLOSURES 0
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
 #define FFI_NATIVE_RAW_API 0
 
 #endif

Index: libffi/src/m68k/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/m68k/sysv.S,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/m68k/sysv.S      30 Jul 2005 19:00:14 -0000      1.2
+++ libffi/src/m68k/sysv.S      30 Nov 2007 20:59:56 -0000      1.3
@@ -8,40 +8,60 @@
 #include <fficonfig.h>
 #include <ffi.h>
 
+#ifdef HAVE_AS_CFI_PSEUDO_OP
+#define CFI_STARTPROC()                .cfi_startproc
+#define CFI_OFFSET(reg,off)    .cfi_offset     reg,off
+#define CFI_DEF_CFA(reg,off)   .cfi_def_cfa    reg,off
+#define CFI_ENDPROC()          .cfi_endproc
+#else
+#define CFI_STARTPROC()
+#define CFI_OFFSET(reg,off)
+#define CFI_DEF_CFA(reg,off)
+#define CFI_ENDPROC()
+#endif
+
        .text
 
        .globl  ffi_call_SYSV
        .type   ffi_call_SYSV,@function
+       .align  4
 
 ffi_call_SYSV:
+       CFI_STARTPROC()
        link    %fp,#0
+       CFI_OFFSET(14,-8)
+       CFI_DEF_CFA(14,8)
        move.l  %d2,-(%sp)
+       CFI_OFFSET(2,-12)
 
        | Make room for all of the new args.
-       sub.l   16(%fp),%sp
+       sub.l   12(%fp),%sp
 
        | Call ffi_prep_args
-       move.l  12(%fp),-(%sp)
+       move.l  8(%fp),-(%sp)
        pea     4(%sp)
-       move.l  8(%fp),%a0
-       jsr     (%a0)
+#if !defined __PIC__
+       jsr     ffi_prep_args
+#else
+       bsr.l   address@hidden
+#endif
        addq.l  #8,%sp  
 
        | Pass pointer to struct value, if any
        move.l  %a0,%a1
 
        | Call the function
-       move.l  32(%fp),%a0
+       move.l  24(%fp),%a0
        jsr     (%a0)
 
        | Remove the space we pushed for the args
-       add.l   16(%fp),%sp
+       add.l   12(%fp),%sp
 
        | Load the pointer to storage for the return value
-       move.l  28(%fp),%a1
+       move.l  20(%fp),%a1
 
        | Load the return type code 
-       move.l  20(%fp),%d2
+       move.l  16(%fp),%d2
 
        | If the return value pointer is NULL, assume no return value.
        tst.l   %a1
@@ -79,19 +99,111 @@
 
 retpointer:
        btst    #5,%d2
-       jbeq    retstruct
+       jbeq    retstruct1
        move.l  %a0,(%a1)
        jbra    epilogue
 
-retstruct:
+retstruct1:
        btst    #6,%d2
+       jbeq    retstruct2
+       move.b  %d0,(%a1)
+       jbra    epilogue
+
+retstruct2:
+       btst    #7,%d2
        jbeq    noretval
-       move.l  24(%fp),%d2
-       bfins   %d0,(%a1){#0,%d2}
+       move.w  %d0,(%a1)
 
 noretval:
 epilogue:
        move.l  (%sp)+,%d2
-       unlk    %a6
+       unlk    %fp
        rts
+       CFI_ENDPROC()
        .size   ffi_call_SYSV,.-ffi_call_SYSV
+
+       .globl  ffi_closure_SYSV
+       .type   ffi_closure_SYSV, @function
+       .align  4
+
+ffi_closure_SYSV:
+       CFI_STARTPROC()
+       link    %fp,#-12
+       CFI_OFFSET(14,-8)
+       CFI_DEF_CFA(14,8)
+       move.l  %sp,-12(%fp)
+       pea     8(%fp)
+       pea     -12(%fp)
+       move.l  %a0,-(%sp)
+#if !defined __PIC__
+       jsr     ffi_closure_SYSV_inner
+#else
+       bsr.l   address@hidden
+#endif
+
+       lsr.l   #1,%d0
+       jne     1f
+       jcc     .Lcls_epilogue
+       move.l  -12(%fp),%d0
+.Lcls_epilogue:
+       unlk    %fp
+       rts
+1:
+       lea     -12(%fp),%a0
+       lsr.l   #2,%d0
+       jne     1f
+       jcs     .Lcls_ret_float
+       move.l  (%a0)+,%d0
+       move.l  (%a0),%d1
+       jra     .Lcls_epilogue
+.Lcls_ret_float:
+       fmove.s (%a0),%fp0
+       jra     .Lcls_epilogue
+1:
+       lsr.l   #2,%d0
+       jne     1f
+       jcs     .Lcls_ret_ldouble
+       fmove.d (%a0),%fp0
+       jra     .Lcls_epilogue
+.Lcls_ret_ldouble:
+       fmove.x (%a0),%fp0
+       jra     .Lcls_epilogue
+1:
+       lsr.l   #2,%d0
+       jne     .Lcls_ret_struct2
+       jcs     .Lcls_ret_struct1
+       move.l  (%a0),%a0
+       move.l  %a0,%d0
+       jra     .Lcls_epilogue
+.Lcls_ret_struct1:
+       move.b  (%a0),%d0
+       jra     .Lcls_epilogue
+.Lcls_ret_struct2:
+       move.w  (%a0),%d0
+       jra     .Lcls_epilogue
+       CFI_ENDPROC()
+
+       .size   ffi_closure_SYSV,.-ffi_closure_SYSV
+
+       .globl  ffi_closure_struct_SYSV
+       .type   ffi_closure_struct_SYSV, @function
+       .align  4
+
+ffi_closure_struct_SYSV:
+       CFI_STARTPROC()
+       link    %fp,#0
+       CFI_OFFSET(14,-8)
+       CFI_DEF_CFA(14,8)
+       move.l  %sp,-12(%fp)
+       pea     8(%fp)
+       move.l  %a1,-(%sp)
+       move.l  %a0,-(%sp)
+#if !defined __PIC__
+       jsr     ffi_closure_SYSV_inner
+#else
+       bsr.l   address@hidden
+#endif
+       unlk    %fp
+       rts
+       CFI_ENDPROC()
+       .size   ffi_closure_struct_SYSV,.-ffi_closure_struct_SYSV

Index: libffi/src/mips/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/mips/ffi.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/mips/ffi.c       30 Jul 2005 19:00:14 -0000      1.3
+++ libffi/src/mips/ffi.c       30 Nov 2007 20:59:56 -0000      1.4
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1996 Red Hat, Inc.
+   ffi.c - Copyright (c) 1996, 2007 Red Hat, Inc.
    
    MIPS Foreign Function Interface 
 
@@ -27,15 +27,20 @@
 #include <ffi_common.h>
 
 #include <stdlib.h>
-#include <sys/cachectl.h>
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_DEBUG
+# define FFI_MIPS_STOP_HERE() ffi_stop_here()
+#else
+# define FFI_MIPS_STOP_HERE() do {} while(0)
+#endif
+
+#ifdef FFI_MIPS_N32
 #define FIX_ARGP \
 FFI_ASSERT(argp <= &stack[bytes]); \
 if (argp == &stack[bytes]) \
 { \
   argp = stack; \
-  ffi_stop_here(); \
+  FFI_MIPS_STOP_HERE(); \
 }
 #else
 #define FIX_ARGP 
@@ -50,17 +55,17 @@
                          int bytes,
                          int flags)
 {
-  register int i;
-  register void **p_argv;
-  register char *argp;
-  register ffi_type **p_arg;
+  int i;
+  void **p_argv;
+  char *argp;
+  ffi_type **p_arg;
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* If more than 8 double words are used, the remainder go
      on the stack. We reorder stuff on the stack here to 
      support this easily. */
-  if (bytes > 8 * FFI_SIZEOF_ARG)
-    argp = &stack[bytes - (8 * FFI_SIZEOF_ARG)];
+  if (bytes > 8 * sizeof(ffi_arg))
+    argp = &stack[bytes - (8 * sizeof(ffi_arg))];
   else
     argp = stack;
 #else
@@ -69,7 +74,7 @@
 
   memset(stack, 0, bytes);
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   if ( ecif->cif->rstruct_flag != 0 )
 #else
   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
@@ -85,92 +90,90 @@
   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
     {
       size_t z;
-      unsigned short a;
+      unsigned int a;
 
-      /* Align if necessary */
+      /* Align if necessary.  */
       a = (*p_arg)->alignment;
-      if (a < FFI_SIZEOF_ARG)
-        a = FFI_SIZEOF_ARG;
+      if (a < sizeof(ffi_arg))
+        a = sizeof(ffi_arg);
       
-      if ((a - 1) & (unsigned) argp) {
+      if ((a - 1) & (unsigned long) argp)
+       {
        argp = (char *) ALIGN(argp, a);
        FIX_ARGP;
       }
 
-#if _MIPS_SIM == _ABIO32
-#define OFFSET 0
-#else
-#define OFFSET sizeof(int)
-#endif      
-
          z = (*p_arg)->size;
-         if (z < sizeof(ffi_arg))
+      if (z <= sizeof(ffi_arg))
            {
+          int type = (*p_arg)->type;
              z = sizeof(ffi_arg);
 
-             switch ((*p_arg)->type)
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type =
+              (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+         switch (type)
                {
                case FFI_TYPE_SINT8:
-                 *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT8 *)(* p_argv);
+               *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
                  break;
                  
                case FFI_TYPE_UINT8:
-                 *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT8 *)(* p_argv);
+               *(ffi_arg *)argp = *(UINT8 *)(* p_argv);
                  break;
                  
                case FFI_TYPE_SINT16:
-                 *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT16 *)(* p_argv);
+               *(ffi_arg *)argp = *(SINT16 *)(* p_argv);
                  break;
                  
                case FFI_TYPE_UINT16:
-                 *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT16 *)(* p_argv);
+               *(ffi_arg *)argp = *(UINT16 *)(* p_argv);
                  break;
                  
                case FFI_TYPE_SINT32:
-                 *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT32 *)(* p_argv);
+               *(ffi_arg *)argp = *(SINT32 *)(* p_argv);
                  break;
                  
                case FFI_TYPE_UINT32:
-               case FFI_TYPE_POINTER:
-                 *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT32 *)(* p_argv);
+               *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
                  break;
 
-                 /* This can only happen with 64bit slots */
+             /* This can only happen with 64bit slots.  */
                case FFI_TYPE_FLOAT:
                  *(float *) argp = *(float *)(* p_argv);
                  break;
 
-                 /* Handle small structures */
-               case FFI_TYPE_STRUCT:
+             /* Handle structures.  */
+             default:
                  memcpy(argp, *p_argv, (*p_arg)->size);
                  break;
-
-               default:
-                 FFI_ASSERT(0);
                }
            }
          else
            {
-#if _MIPS_SIM == _ABIO32             
+#ifdef FFI_MIPS_O32
              memcpy(argp, *p_argv, z);
 #else
              {
-               unsigned end = (unsigned) argp+z;
-               unsigned cap = (unsigned) stack+bytes;
+           unsigned long end = (unsigned long) argp + z;
+           unsigned long cap = (unsigned long) stack + bytes;
 
-               /* Check if the data will fit within the register
-                  space. Handle it if it doesn't. */
+           /* Check if the data will fit within the register space.
+              Handle it if it doesn't.  */
 
                if (end <= cap)
                  memcpy(argp, *p_argv, z);
                else
                  {
-                   unsigned portion = end - cap;
+               unsigned long portion = cap - (unsigned long)argp;
 
                    memcpy(argp, *p_argv, portion);
                    argp = stack;
-                   memcpy(argp, 
-                          (void*)((unsigned)(*p_argv)+portion), z - portion);
+                z -= portion;
+               memcpy(argp, (void*)((unsigned long)(*p_argv) + portion),
+                       z);
                  }
              }
 #endif
@@ -179,11 +182,9 @@
          argp += z;
          FIX_ARGP;
     }
-  
-  return;
 }
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
 
 /* The n32 spec says that if "a chunk consists solely of a double 
    float field (but not a double, which is part of a union), it
@@ -191,35 +192,41 @@
    passed in an integer register". This code traverses structure
    definitions and generates the appropriate flags. */
 
-unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
+static unsigned
+calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg)
 {
   unsigned flags = 0;
   unsigned index = 0;
 
   ffi_type *e;
 
-  while (e = arg->elements[index])
+  while ((e = arg->elements[index]))
     {
+      /* Align this object.  */
+      *loc = ALIGN(*loc, e->alignment);
       if (e->type == FFI_TYPE_DOUBLE)
        {
-         flags += (FFI_TYPE_DOUBLE << *shift);
-         *shift += FFI_FLAG_BITS;
+          /* Already aligned to FFI_SIZEOF_ARG.  */
+          *arg_reg = *loc / FFI_SIZEOF_ARG;
+          if (*arg_reg > 7)
+            break;
+         flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
+          *loc += e->size;
        }
-      else if (e->type == FFI_TYPE_STRUCT)
-         flags += calc_n32_struct_flags(e, shift);
       else
-       *shift += FFI_FLAG_BITS;
-
+        *loc += e->size;
       index++;
     }
+  /* Next Argument register at alignment of FFI_SIZEOF_ARG.  */
+  *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 
   return flags;
 }
 
-unsigned calc_n32_return_struct_flags(ffi_type *arg)
+static unsigned
+calc_n32_return_struct_flags(ffi_type *arg)
 {
   unsigned flags = 0;
-  unsigned index = 0;
   unsigned small = FFI_TYPE_SMALLSTRUCT;
   ffi_type *e;
 
@@ -238,16 +245,16 @@
 
   e = arg->elements[0];
   if (e->type == FFI_TYPE_DOUBLE)
-    flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+    flags = FFI_TYPE_DOUBLE;
   else if (e->type == FFI_TYPE_FLOAT)
-    flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+    flags = FFI_TYPE_FLOAT;
 
   if (flags && (e = arg->elements[1]))
     {
       if (e->type == FFI_TYPE_DOUBLE)
-       flags += FFI_TYPE_DOUBLE;
+       flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
       else if (e->type == FFI_TYPE_FLOAT)
-       flags += FFI_TYPE_FLOAT;
+       flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
       else 
        return small;
 
@@ -272,7 +279,7 @@
 {
   cif->flags = 0;
 
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
   /* Set the flags necessary for O32 processing.  FFI_O32_SOFT_FLOAT
    * does not have special handling for floating point args.
    */
@@ -360,10 +367,11 @@
     }
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* Set the flags necessary for N32 processing */
   {
-    unsigned shift = 0;
+    unsigned arg_reg = 0;
+    unsigned loc = 0;
     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
     unsigned index = 0;
 
@@ -378,7 +386,7 @@
            /* This means that the structure is being passed as
               a hidden argument */
 
-           shift = FFI_FLAG_BITS;
+           arg_reg = 1;
            count = (cif->nargs < 7) ? cif->nargs : 7;
 
            cif->rstruct_flag = !0;
@@ -389,23 +397,37 @@
     else
       cif->rstruct_flag = 0;
 
-    while (count-- > 0)
+    while (count-- > 0 && arg_reg < 8)
       {
        switch ((cif->arg_types)[index]->type)
          {
          case FFI_TYPE_FLOAT:
          case FFI_TYPE_DOUBLE:
-           cif->flags += ((cif->arg_types)[index]->type << shift);
-           shift += FFI_FLAG_BITS;
+           cif->flags +=
+              ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
+           arg_reg++;
+           break;
+          case FFI_TYPE_LONGDOUBLE:
+            /* Align it.  */
+            arg_reg = ALIGN(arg_reg, 2);
+            /* Treat it as two adjacent doubles.  */
+           cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
+           cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
            break;
 
          case FFI_TYPE_STRUCT:
+            loc = arg_reg * FFI_SIZEOF_ARG;
            cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
-                                               &shift);
+                                               &loc, &arg_reg);
            break;
 
          default:
-           shift += FFI_FLAG_BITS;
+           arg_reg++;
+            break;
          }
 
        index++;
@@ -479,7 +501,7 @@
     
   switch (cif->abi) 
     {
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
     case FFI_O32:
     case FFI_O32_SOFT_FLOAT:
       ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, 
@@ -487,10 +509,25 @@
       break;
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
     case FFI_N32:
+    case FFI_N64:
+      {
+        int copy_rvalue = 0;
+        void *rvalue_copy = ecif.rvalue;
+        if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16)
+          {
+            /* For structures smaller than 16 bytes we clobber memory
+               in 8 byte increments.  Make a copy so we don't clobber
+               the callers memory outside of the struct bounds.  */
+            rvalue_copy = alloca(16);
+            copy_rvalue = 1;
+          }
       ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, 
-                  cif->flags, ecif.rvalue, fn);
+                     cif->flags, rvalue_copy, fn);
+        if (copy_rvalue)
+          memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size);
+      }
       break;
 #endif
 
@@ -500,41 +537,79 @@
     }
 }
 
-#if FFI_CLOSURES  /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if FFI_CLOSURES
 #if defined(FFI_MIPS_O32)
 extern void ffi_closure_O32(void);
+#else
+extern void ffi_closure_N32(void);
 #endif /* FFI_MIPS_O32 */
 
 ffi_status
-ffi_prep_closure (ffi_closure *closure,
+ffi_prep_closure_loc (ffi_closure *closure,
                  ffi_cif *cif,
                  void (*fun)(ffi_cif*,void*,void**,void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
-  unsigned int fn;
-  unsigned int ctx = (unsigned int) closure;
+  void * fn;
+  char *clear_location = (char *) codeloc;
 
 #if defined(FFI_MIPS_O32)
   FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
-  fn = (unsigned int) ffi_closure_O32;
+  fn = ffi_closure_O32;
 #else /* FFI_MIPS_N32 */
-  FFI_ASSERT(cif->abi == FFI_N32);
-  FFI_ASSERT(!"not implemented");
+  FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64);
+  fn = ffi_closure_N32;
 #endif /* FFI_MIPS_O32 */
 
-  tramp[0] = 0x3c190000 | (fn >> 16);     /* lui  $25,high(fn) */
-  tramp[1] = 0x3c080000 | (ctx >> 16);    /* lui  $8,high(ctx) */
-  tramp[2] = 0x37390000 | (fn & 0xffff);  /* ori  $25,low(fn)  */
-  tramp[3] = 0x03200008;                  /* jr   $25          */
-  tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori  $8,low(ctx)  */
+#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned)fn >> 16);
+  /* ori  $25,low(fn)  */
+  tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff);
+  /* lui  $12,high(codeloc) */
+  tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16);
+  /* jr   $25          */
+  tramp[3] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff);
+#else
+  /* N64 has a somewhat larger trampoline.  */
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48);
+  /* lui  $12,high(codeloc) */
+  tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48);
+  /* ori  $25,mid-high(fn)  */
+  tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff);
+  /* ori  $12,mid-high(codeloc)  */
+  tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[4] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[5] = 0x000c6438;
+  /* ori  $25,mid-low(fn)  */
+  tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff);
+  /* ori  $12,mid-low(codeloc)  */
+  tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[8] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[9] = 0x000c6438;
+  /* ori  $25,low(fn)  */
+  tramp[10] = 0x37390000 | ((unsigned long)fn  & 0xffff);
+  /* jr   $25          */
+  tramp[11] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff);
+
+#endif
 
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
 
-  /* XXX this is available on Linux, but anything else? */
-  cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
+  __builtin___clear_cache(clear_location, clear_location + 
FFI_TRAMPOLINE_SIZE);
 
   return FFI_OK;
 }
@@ -558,23 +633,25 @@
  */
 int
 ffi_closure_mips_inner_O32 (ffi_closure *closure,
-                           void *rvalue, unsigned long *ar,
+                           void *rvalue, ffi_arg *ar,
                            double *fpr)
 {
   ffi_cif *cif;
-  void **avalue;
+  void **avaluep;
+  ffi_arg *avalue;
   ffi_type **arg_types;
   int i, avn, argn, seen_int;
 
   cif = closure->cif;
-  avalue = alloca (cif->nargs * sizeof (void *));
+  avalue = alloca (cif->nargs * sizeof (ffi_arg));
+  avaluep = alloca (cif->nargs * sizeof (ffi_arg));
 
   seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
   argn = 0;
 
   if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
     {
-      rvalue = (void *) ar[0];
+      rvalue = (void *)(UINT32)ar[0];
       argn = 1;
     }
 
@@ -588,13 +665,43 @@
          (arg_types[i]->type == FFI_TYPE_FLOAT ||
           arg_types[i]->type == FFI_TYPE_DOUBLE))
        {
-         avalue[i] = ((char *) &fpr[i]);
+#ifdef __MIPSEB__
+         if (arg_types[i]->type == FFI_TYPE_FLOAT)
+           avaluep[i] = ((char *) &fpr[i]) + sizeof (float);
+         else
+#endif
+           avaluep[i] = (char *) &fpr[i];
        }
       else
        {
          if (arg_types[i]->alignment == 8 && (argn & 0x1))
            argn++;
-         avalue[i] = ((char *) &ar[argn]);
+         switch (arg_types[i]->type)
+           {
+             case FFI_TYPE_SINT8:
+               avaluep[i] = &avalue[i];
+               *(SINT8 *) &avalue[i] = (SINT8) ar[argn];
+               break;
+
+             case FFI_TYPE_UINT8:
+               avaluep[i] = &avalue[i];
+               *(UINT8 *) &avalue[i] = (UINT8) ar[argn];
+               break;
+                 
+             case FFI_TYPE_SINT16:
+               avaluep[i] = &avalue[i];
+               *(SINT16 *) &avalue[i] = (SINT16) ar[argn];
+               break;
+                 
+             case FFI_TYPE_UINT16:
+               avaluep[i] = &avalue[i];
+               *(UINT16 *) &avalue[i] = (UINT16) ar[argn];
+               break;
+
+             default:
+               avaluep[i] = (char *) &ar[argn];
+               break;
+           }
          seen_int = 1;
        }
       argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
@@ -602,7 +709,7 @@
     }
 
   /* Invoke the closure. */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  (closure->fun) (cif, rvalue, avaluep, closure->user_data);
 
   if (cif->abi == FFI_O32_SOFT_FLOAT)
     {
@@ -622,4 +729,177 @@
     }
 }
 
+#if defined(FFI_MIPS_N32)
+
+static void
+copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
+                int argn, unsigned arg_offset, ffi_arg *ar,
+                ffi_arg *fpr)
+{
+  ffi_type **elt_typep = type->elements;
+  while(*elt_typep)
+    {
+      ffi_type *elt_type = *elt_typep;
+      unsigned o;
+      char *tp;
+      char *argp;
+      char *fpp;
+
+      o = ALIGN(offset, elt_type->alignment);
+      arg_offset += o - offset;
+      offset = o;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+
+      argp = (char *)(ar + argn);
+      fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
+
+      tp = target + offset;
+
+      if (elt_type->type == FFI_TYPE_DOUBLE)
+        *(double *)tp = *(double *)fpp;
+      else
+        memcpy(tp, argp + arg_offset, elt_type->size);
+
+      offset += elt_type->size;
+      arg_offset += elt_type->size;
+      elt_typep++;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+    }
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer
+ * arguments. FPR is a pointer to the area where floating point
+ * registers have been saved.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return flags.
+ *
+ */
+int
+ffi_closure_mips_inner_N32 (ffi_closure *closure,
+                           void *rvalue, ffi_arg *ar,
+                           ffi_arg *fpr)
+{
+  ffi_cif *cif;
+  void **avaluep;
+  ffi_arg *avalue;
+  ffi_type **arg_types;
+  int i, avn, argn;
+
+  cif = closure->cif;
+  avalue = alloca (cif->nargs * sizeof (ffi_arg));
+  avaluep = alloca (cif->nargs * sizeof (ffi_arg));
+
+  argn = 0;
+
+  if (cif->rstruct_flag)
+    {
+#if _MIPS_SIM==_ABIN32
+      rvalue = (void *)(UINT32)ar[0];
+#else /* N64 */
+      rvalue = (void *)ar[0];
+#endif
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  while (i < avn)
+    {
+      if (arg_types[i]->type == FFI_TYPE_FLOAT
+          || arg_types[i]->type == FFI_TYPE_DOUBLE)
+        {
+          ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn;
+#ifdef __MIPSEB__
+          if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8)
+            avaluep[i] = ((char *) argp) + sizeof (float);
+          else
+#endif
+            avaluep[i] = (char *) argp;
+        }
+      else
+        {
+          unsigned type = arg_types[i]->type;
+
+          if (arg_types[i]->alignment > sizeof(ffi_arg))
+            argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
+
+          ffi_arg *argp = ar + argn;
+
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+          switch (type)
+            {
+            case FFI_TYPE_SINT8:
+              avaluep[i] = &avalue[i];
+              *(SINT8 *) &avalue[i] = (SINT8) *argp;
+              break;
+
+            case FFI_TYPE_UINT8:
+              avaluep[i] = &avalue[i];
+              *(UINT8 *) &avalue[i] = (UINT8) *argp;
+              break;
+
+            case FFI_TYPE_SINT16:
+              avaluep[i] = &avalue[i];
+              *(SINT16 *) &avalue[i] = (SINT16) *argp;
+              break;
+
+            case FFI_TYPE_UINT16:
+              avaluep[i] = &avalue[i];
+              *(UINT16 *) &avalue[i] = (UINT16) *argp;
+              break;
+
+            case FFI_TYPE_SINT32:
+              avaluep[i] = &avalue[i];
+              *(SINT32 *) &avalue[i] = (SINT32) *argp;
+              break;
+
+            case FFI_TYPE_UINT32:
+              avaluep[i] = &avalue[i];
+              *(UINT32 *) &avalue[i] = (UINT32) *argp;
+              break;
+
+            case FFI_TYPE_STRUCT:
+              if (argn < 8)
+                {
+                  /* Allocate space for the struct as at least part of
+                     it was passed in registers.  */
+                  avaluep[i] = alloca(arg_types[i]->size);
+                  copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
+                                  argn, 0, ar, fpr);
+
+                  break;
+                }
+              /* Else fall through.  */
+            default:
+              avaluep[i] = (char *) argp;
+              break;
+            }
+        }
+      argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
+      i++;
+    }
+
+  /* Invoke the closure. */
+  (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+
+  return cif->flags >> (FFI_FLAG_BITS * 8);
+}
+
+#endif /* FFI_MIPS_N32 */
+
 #endif /* FFI_CLOSURES */

Index: libffi/src/mips/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/mips/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/mips/ffitarget.h 30 Jul 2005 19:00:14 -0000      1.1
+++ libffi/src/mips/ffitarget.h 30 Nov 2007 20:59:56 -0000      1.2
@@ -26,17 +26,13 @@
 #ifndef LIBFFI_TARGET_H
 #define LIBFFI_TARGET_H
 
-#ifndef LIBFFI_ASM
-#include <sgidefs.h>
-#endif
-
 #if !defined(_MIPS_SIM)
 -- something is very wrong --
 #else
 #  if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && 
defined(_ABI64))
 #    define FFI_MIPS_N32
 #  else
-#    if _MIPS_SIM==_ABIO32 && defined(_ABIO32)
+#    if (_MIPS_SIM==_ABIO32 && defined(_ABIO32))
 #      define FFI_MIPS_O32
 #    else
 -- this is an unsupported platform --
@@ -108,19 +104,28 @@
 #define ra $31         
 
 #ifdef FFI_MIPS_O32
-#define REG_L  lw
-#define REG_S  sw
-#define SUBU   subu
-#define ADDU   addu
-#define SRL    srl
-#define LI     li
+# define REG_L lw
+# define REG_S sw
+# define SUBU  subu
+# define ADDU  addu
+# define SRL   srl
+# define LI    li
 #else /* !FFI_MIPS_O32 */
-#define REG_L  ld
-#define REG_S  sd
-#define SUBU   dsubu
-#define ADDU   daddu
-#define SRL    dsrl
-#define LI     dli
+# define REG_L ld
+# define REG_S sd
+# define SUBU  dsubu
+# define ADDU  daddu
+# define SRL   dsrl
+# define LI    dli
+# if (_MIPS_SIM==_ABI64)
+#  define LA dla
+#  define EH_FRAME_ALIGN 3
+#  define FDE_ADDR_BYTES .8byte
+# else
+#  define LA la
+#  define EH_FRAME_ALIGN 2
+#  define FDE_ADDR_BYTES .4byte
+# endif /* _MIPS_SIM==_ABI64 */
 #endif /* !FFI_MIPS_O32 */
 #else /* !LIBFFI_ASM */
 #ifdef FFI_MIPS_O32
@@ -147,7 +152,11 @@
   FFI_DEFAULT_ABI = FFI_O32,
 #endif
 #else
+# if _MIPS_SIM==_ABI64
+  FFI_DEFAULT_ABI = FFI_N64,
+# else
   FFI_DEFAULT_ABI = FFI_N32,
+# endif
 #endif
 
   FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
@@ -162,8 +171,13 @@
 #define FFI_CLOSURES 1
 #define FFI_TRAMPOLINE_SIZE 20
 #else
-/* N32/N64 not implemented yet. */
-#define FFI_CLOSURES 0
+/* N32/N64. */
+# define FFI_CLOSURES 1
+#if _MIPS_SIM==_ABI64
+#define FFI_TRAMPOLINE_SIZE 52
+#else
+#define FFI_TRAMPOLINE_SIZE 20
+#endif
 #endif /* FFI_MIPS_O32 */
 #define FFI_NATIVE_RAW_API 0
 

Index: libffi/src/mips/n32.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/mips/n32.S,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/mips/n32.S       30 Jul 2005 19:00:14 -0000      1.2
+++ libffi/src/mips/n32.S       30 Nov 2007 20:59:56 -0000      1.3
@@ -45,13 +45,19 @@
        .globl  ffi_call_N32
        .ent    ffi_call_N32
 ffi_call_N32:  
+.LFB3:
+       .frame  $fp, SIZEOF_FRAME, ra
+       .mask   0xc0000000,-FFI_SIZEOF_ARG
+       .fmask  0x00000000,0
 
        # Prologue
        SUBU    $sp, SIZEOF_FRAME                       # Frame size
+.LCFI0:
        REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame 
pointer
        REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return 
address
+.LCFI1:
        move    $fp, $sp
-
+.LCFI3:
        move    t9, callback    # callback function pointer
        REG_S   bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
        REG_S   flags, 3*FFI_SIZEOF_ARG($fp) # flags
@@ -315,6 +321,224 @@
        ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
        j       ra
 
+.LFE3:
        .end    ffi_call_N32
        
+/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
+   ($12). Stores any arguments passed in registers onto the stack,
+   then calls ffi_closure_mips_inner_N32, which then decodes
+   them.
+       
+       Stack layout:
+
+       20 - Start of parameters, original sp
+       19 - Called function a7 save
+       18 - Called function a6 save
+       17 - Called function a5 save
+       16 - Called function a4 save
+       15 - Called function a3 save
+       14 - Called function a2 save
+       13 - Called function a1 save
+       12 - Called function a0 save
+       11 - Called function f19
+       10 - Called function f18
+        9 - Called function f17
+        8 - Called function f16
+        7 - Called function f15
+         6 - Called function f14
+         5 - Called function f13
+         4 - Called function f12
+        3 - return value high (v1 or $f2)
+        2 - return value low (v0 or $f0)
+        1 - ra save
+        0 - gp save our sp  points here
+        */
+
+#define SIZEOF_FRAME2  (20 * FFI_SIZEOF_ARG)
+       
+#define A7_OFF2                (19 * FFI_SIZEOF_ARG)
+#define A6_OFF2                (18 * FFI_SIZEOF_ARG)
+#define A5_OFF2                (17 * FFI_SIZEOF_ARG)
+#define A4_OFF2                (16 * FFI_SIZEOF_ARG)
+#define A3_OFF2                (15 * FFI_SIZEOF_ARG)
+#define A2_OFF2                (14 * FFI_SIZEOF_ARG)
+#define A1_OFF2                (13 * FFI_SIZEOF_ARG)
+#define A0_OFF2                (12 * FFI_SIZEOF_ARG)   
+
+#define F19_OFF2       (11 * FFI_SIZEOF_ARG)
+#define F18_OFF2       (10 * FFI_SIZEOF_ARG)
+#define F17_OFF2       (9  * FFI_SIZEOF_ARG)
+#define F16_OFF2       (8  * FFI_SIZEOF_ARG)
+#define F15_OFF2       (7  * FFI_SIZEOF_ARG)
+#define F14_OFF2       (6  * FFI_SIZEOF_ARG)
+#define F13_OFF2       (5  * FFI_SIZEOF_ARG)
+#define F12_OFF2       (4  * FFI_SIZEOF_ARG)
+
+#define V1_OFF2                (3  * FFI_SIZEOF_ARG)
+#define V0_OFF2                (2  * FFI_SIZEOF_ARG)
+
+#define RA_OFF2                (1  * FFI_SIZEOF_ARG)
+#define GP_OFF2                (0  * FFI_SIZEOF_ARG)
+
+       .align  2
+       .globl  ffi_closure_N32
+       .ent    ffi_closure_N32
+ffi_closure_N32:
+.LFB2:
+       .frame  $sp, SIZEOF_FRAME2, ra
+       .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
+       .fmask  0x00000000,0
+       SUBU    $sp, SIZEOF_FRAME2
+.LCFI5:
+       .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)
+       REG_S   a6, A6_OFF2($sp)
+       REG_S   a7, A7_OFF2($sp)
+
+       # Store all possible float/double registers.
+       s.d     $f12, F12_OFF2($sp)
+       s.d     $f13, F13_OFF2($sp)
+       s.d     $f14, F14_OFF2($sp)
+       s.d     $f15, F15_OFF2($sp)
+       s.d     $f16, F16_OFF2($sp)
+       s.d     $f17, F17_OFF2($sp)
+       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
+       bne     v0, FFI_TYPE_INT, cls_retfloat
+       REG_L   v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retfloat:
+       bne     v0, FFI_TYPE_FLOAT, cls_retdouble
+       l.s     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retdouble: 
+       bne     v0, FFI_TYPE_DOUBLE, cls_retstruct_d
+       l.d     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retstruct_d:       
+       bne     v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
+       l.d     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f:       
+       bne     v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
+       l.s     $f0, V0_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_d_d:     
+       bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
+       l.d     $f0, V0_OFF2($sp)
+       l.d     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f_f:     
+       bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
+       l.s     $f0, V0_OFF2($sp)
+       l.s     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_d_f:     
+       bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
+       l.d     $f0, V0_OFF2($sp)
+       l.s     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_f_d:     
+       bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
+       l.s     $f0, V0_OFF2($sp)
+       l.d     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+       
+cls_retstruct_small2:  
+       REG_L   v0, V0_OFF2($sp)
+       REG_L   v1, V1_OFF2($sp)
+       
+       # Epilogue
+cls_epilogue:  
+       REG_L   ra,  RA_OFF2($sp)        # Restore return address
+       .cpreturn
+       ADDU    $sp, SIZEOF_FRAME2
+       j       ra
+.LFE2: 
+       .end    ffi_closure_N32
+
+        .section        .eh_frame,"aw",@progbits
+.Lframe1:
+        .4byte  .LECIE1-.LSCIE1                # length
+.LSCIE1:
+        .4byte  0x0                    # CIE
+        .byte   0x1                    # Version 1
+        .ascii  "\000"                 # Augmentation
+        .uleb128 0x1                   # Code alignment 1
+        .sleb128 -4                    # Data alignment -4
+        .byte   0x1f                   # Return Address $31
+        .byte   0xc                    # DW_CFA_def_cfa
+        .uleb128 0x1d                  # in $sp
+        .uleb128 0x0                   # offset 0
+        .align  EH_FRAME_ALIGN
+.LECIE1:
+
+.LSFDE1:
+        .4byte  .LEFDE1-.LASFDE1       # length.
+.LASFDE1:
+        .4byte  .LASFDE1-.Lframe1      # CIE_pointer.
+        FDE_ADDR_BYTES  .LFB3          # initial_location.
+        FDE_ADDR_BYTES  .LFE3-.LFB3    # address_range.
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI0-.LFB3           # to .LCFI0
+        .byte   0xe                    # DW_CFA_def_cfa_offset
+        .uleb128 SIZEOF_FRAME          # adjust stack.by SIZEOF_FRAME
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI1-.LCFI0          # to .LCFI1
+        .byte   0x9e                   # DW_CFA_offset of $fp
+        .uleb128 2*FFI_SIZEOF_ARG/4    # 
+        .byte   0x9f                   # DW_CFA_offset of ra
+        .uleb128 1*FFI_SIZEOF_ARG/4    # 
+        .byte   0x4                    # DW_CFA_advance_loc4
+        .4byte  .LCFI3-.LCFI1          # to .LCFI3
+        .byte   0xd                    # DW_CFA_def_cfa_register
+        .uleb128 0x1e                  # in $fp
+        .align  EH_FRAME_ALIGN
+.LEFDE1:
+.LSFDE3:
+       .4byte  .LEFDE3-.LASFDE3        # length
+.LASFDE3:
+       .4byte  .LASFDE3-.Lframe1       # CIE_pointer.
+       FDE_ADDR_BYTES  .LFB2           # initial_location.
+       FDE_ADDR_BYTES  .LFE2-.LFB2     # address_range.
+       .byte   0x4                     # DW_CFA_advance_loc4
+       .4byte  .LCFI5-.LFB2            # to .LCFI5
+       .byte   0xe                     # DW_CFA_def_cfa_offset
+       .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
+       .byte   0x4                     # DW_CFA_advance_loc4
+       .4byte  .LCFI6-.LCFI5           # to .LCFI6
+       .byte   0x9c                    # DW_CFA_offset of $gp ($28)
+       .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
+       .byte   0x9f                    # DW_CFA_offset of ra ($31)
+       .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
+       .align  EH_FRAME_ALIGN
+.LEFDE3:
+       
 #endif

Index: libffi/src/mips/o32.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/mips/o32.S,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/mips/o32.S       30 Jul 2005 19:00:14 -0000      1.2
+++ libffi/src/mips/o32.S       30 Nov 2007 20:59:56 -0000      1.3
@@ -35,7 +35,10 @@
 #define bytes   a2
 #define flags   a3
                
-#define SIZEOF_FRAME   ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
+#define SIZEOF_FRAME   (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
+#define A3_OFF         (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
+#define FP_OFF         (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
+#define RA_OFF         (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
 
        .abicalls
        .text
@@ -47,42 +50,36 @@
        # Prologue
        SUBU    $sp, SIZEOF_FRAME                       # Frame size
 $LCFI0:
-       REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame 
pointer
+       REG_S   $fp, FP_OFF($sp)        # Save frame pointer
 $LCFI1:
-       REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return 
address
+       REG_S   ra, RA_OFF($sp)         # Save return address
 $LCFI2:
        move    $fp, $sp
 
 $LCFI3:
        move    t9, callback    # callback function pointer
-       REG_S   flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
+       REG_S   flags, A3_OFF($fp)      # flags
 
        # Allocate at least 4 words in the argstack
-       move    v0, bytes
-       bge     bytes, 4 * FFI_SIZEOF_ARG, bigger       
        LI      v0, 4 * FFI_SIZEOF_ARG
-       b       sixteen
+       blt     bytes, v0, sixteen
 
-bigger:        
-       ADDU    t0, v0, 2 * FFI_SIZEOF_ARG -1   # make sure it is aligned 
-       and     v0, t0, -2 * FFI_SIZEOF_ARG             # to an 8 byte boundry
+       ADDU    v0, bytes, 7    # make sure it is aligned 
+       and     v0, -8          # to an 8 byte boundry
 
 sixteen:
-       SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
+       SUBU    $sp, v0         # move the stack pointer to reflect the
                                # arg space
 
        ADDU    a0, $sp, 4 * FFI_SIZEOF_ARG
-       ADDU    a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
 
        jalr    t9
        
-       REG_L   t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp)  # load the flags word
-       add     t2, t0, 0                          # and copy it into t2
-
+       REG_L   t0, A3_OFF($fp)         # load the flags word
+       SRL     t2, t0, 4               # shift our arg info
        and     t0, ((1<<4)-1)          # mask out the return type
-       SRL     t2, 4                   # shift our arg info
                
-       ADDU    $sp, $sp, 4 * FFI_SIZEOF_ARG    # adjust $sp to new args
+       ADDU    $sp, 4 * FFI_SIZEOF_ARG         # adjust $sp to new args
 
        bnez    t0, pass_d                      # make it quick for int
        REG_L   a0, 0*FFI_SIZEOF_ARG($sp)               # just go ahead and 
load the
@@ -176,8 +173,8 @@
        # Epilogue
 epilogue:      
        move    $sp, $fp        
-       REG_L   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame 
pointer
-       REG_L   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)  # Restore return 
address
+       REG_L   $fp, FP_OFF($sp)        # Restore frame pointer
+       REG_L   ra, RA_OFF($sp)         # Restore return address
        ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
        j       ra
 
@@ -186,30 +183,47 @@
 
 
 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
-       in t0. Stores any arguments passed in registers onto the
+       in t4 ($12). Stores any arguments passed in registers onto the
        stack, then calls ffi_closure_mips_inner_O32, which
        then decodes them.
        
        Stack layout:
 
-       14 - Start of parameters, original sp
-       13 - ra save
-       12 - fp save
-       11 - $16 (s0) save
-       10 - cprestore
-        9 - return value high (v1)
-        8 - return value low (v0)
-        7 - f14 (le high, be low)
-        6 - f14 (le low, be high)
-        5 - f12 (le high, be low)
-        4 - f12 (le low, be high)
-        3 - Called function a3 save
-        2 - Called function a2 save
-        1 - Called function a1 save
-        0 - Called function a0 save our sp, fp point here
+        3 - a3 save
+        2 - a2 save
+        1 - a1 save
+        0 - a0 save, original sp
+       -1 - ra save
+       -2 - fp save
+       -3 - $16 (s0) save
+       -4 - cprestore
+       -5 - return value high (v1)
+       -6 - return value low (v0)
+       -7 - f14 (le high, be low)
+       -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
         */
        
-#define SIZEOF_FRAME2  ( 14 * FFI_SIZEOF_ARG )
+#define SIZEOF_FRAME2  (14 * 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)
+#define A0_OFF2                (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
+#define RA_OFF2                (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
+#define FP_OFF2                (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
+#define S0_OFF2                (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
+#define GP_OFF2                (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
+#define V1_OFF2                (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
+#define V0_OFF2                (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
+#define FA_1_1_OFF2    (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
+#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)
 
        .text
        .align  2
@@ -218,45 +232,45 @@
 ffi_closure_O32:
 $LFB1:
        # Prologue
-       .frame  $fp, SIZEOF_FRAME2, $31
+       .frame  $fp, SIZEOF_FRAME2, ra
        .set    noreorder
-       .cpload $25
+       .cpload t9
        .set    reorder
        SUBU    $sp, SIZEOF_FRAME2
-       .cprestore SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG
+       .cprestore GP_OFF2
 $LCFI4:
-       REG_S   $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)       # Save s0
-       REG_S   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Save frame 
pointer
-       REG_S   ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)        # Save return 
address
+       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
 $LCFI6:
        move    $fp, $sp
 
 $LCFI7:
        # Store all possible argument registers. If there are more than
-       # four arguments, then they should be stored above where we put $7.
-       REG_S   $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
-       REG_S   $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
-       REG_S   $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
-       REG_S   $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
+       # four arguments, then they are stored above where we put a3.
+       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 $16
-       REG_L   $16, 20($8)     # cif pointer follows tramp.
+       # Load ABI enum to s0
+       REG_L   $16, 20($12)    # cif pointer follows tramp.
        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, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
-       s.d     $f14, SIZEOF_FRAME2 -  8*FFI_SIZEOF_ARG($fp)
+       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.
-       la      $25, ffi_closure_mips_inner_O32
-       move    $4, $8   # Pointer to the ffi_closure
-       addu    $5, $fp, SIZEOF_FRAME2 -  6*FFI_SIZEOF_ARG
-       addu    $6, $fp, SIZEOF_FRAME2 +  0*FFI_SIZEOF_ARG
-       addu    $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
-       jalr    $31, $25
+       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
+       jalr    t9
 
        # Load the return value into the appropriate register.
        move    $8, $2
@@ -267,28 +281,22 @@
        bne     $16, $13, 1f    # Skip fp restore if FFI_O32_SOFT_FLOAT
 
        li      $9, FFI_TYPE_FLOAT
-       l.s     $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
+       l.s     $f0, V0_OFF2($fp)
        beq     $8, $9, closure_done
 
        li      $9, FFI_TYPE_DOUBLE
-       l.d     $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
+       l.d     $f0, V0_OFF2($fp)
        beq     $8, $9, closure_done
 1:     
-       li      $9, FFI_TYPE_SINT64
-       REG_L   $3, SIZEOF_FRAME2 - 5*FFI_SIZEOF_ARG($fp)
-       beq     $8, $9, integer
-       li      $9, FFI_TYPE_UINT64
-       beq     $8, $9, integer
-
-integer:
-       REG_L   $2, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
+       REG_L   $3, V1_OFF2($fp)
+       REG_L   $2, V0_OFF2($fp)
 
 closure_done:
        # Epilogue
        move    $sp, $fp
-       REG_L   $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)       # Restore s0
-       REG_L   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Restore 
frame pointer
-       REG_L   ra,  SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)       # Restore 
return address
+       REG_L   $16, S0_OFF2($sp)        # Restore s0
+       REG_L   $fp, FP_OFF2($sp)        # Restore frame pointer
+       REG_L   ra,  RA_OFF2($sp)        # Restore return address
        ADDU    $sp, SIZEOF_FRAME2
        j       ra
 $LFE1:

Index: libffi/src/pa/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/pa/ffi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/pa/ffi.c 30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/pa/ffi.c 30 Nov 2007 20:59:56 -0000      1.2
@@ -2,6 +2,7 @@
    ffi.c - (c) 2003-2004 Randolph Chung <address@hidden>
 
    HPPA Foreign Function Interface
+   HP-UX PA ABI support (c) 2006 Free Software Foundation, Inc.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -30,15 +31,19 @@
 #include <stdio.h>
 
 #define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
-#define ROUND_DOWN(v, a)  (((size_t)(v) - (a) + 1) & ~((a) - 1))
+
 #define MIN_STACK_SIZE  64
 #define FIRST_ARG_SLOT  9
 #define DEBUG_LEVEL   0
 
-#define fldw(addr, fpreg) asm volatile ("fldw 0(%0), %%" #fpreg "L" : : 
"r"(addr) : #fpreg)
-#define fstw(fpreg, addr) asm volatile ("fstw %%" #fpreg "L, 0(%0)" : : 
"r"(addr))
-#define fldd(addr, fpreg) asm volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) 
: #fpreg)
-#define fstd(fpreg, addr) asm volatile ("fstd %%" #fpreg "L, 0(%0)" : : 
"r"(addr))
+#define fldw(addr, fpreg) \
+  __asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
+#define fstw(fpreg, addr) \
+  __asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
+#define fldd(addr, fpreg) \
+  __asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
+#define fstd(fpreg, addr) \
+  __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
 
 #define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while 
(0)
 
@@ -47,16 +52,19 @@
   size_t sz = t->size;
 
   /* Small structure results are passed in registers,
-     larger ones are passed by pointer.  */
+     larger ones are passed by pointer.  Note that
+     small structures of size 2, 4 and 8 differ from
+     the corresponding integer types in that they have
+     different alignment requirements.  */
 
   if (sz <= 1)
     return FFI_TYPE_UINT8;
   else if (sz == 2)
-    return FFI_TYPE_UINT16;
+    return FFI_TYPE_SMALL_STRUCT2;
   else if (sz == 3)
     return FFI_TYPE_SMALL_STRUCT3;
   else if (sz == 4)
-    return FFI_TYPE_UINT32;
+    return FFI_TYPE_SMALL_STRUCT4;
   else if (sz == 5)
     return FFI_TYPE_SMALL_STRUCT5;
   else if (sz == 6)
@@ -64,7 +72,7 @@
   else if (sz == 7)
     return FFI_TYPE_SMALL_STRUCT7;
   else if (sz <= 8)
-    return FFI_TYPE_UINT64;
+    return FFI_TYPE_SMALL_STRUCT8;
   else
     return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
 }
@@ -86,13 +94,32 @@
    SP-20                RP
    SP-4                 previous SP
   
-   First 4 non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23
-   First 2 non-FP 64-bit args are passed in register pairs, starting
-     on an even numbered register (i.e. r26/r25 and r24+r23)
-   First 4 FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L
-   First 2 FP 64-bit arguments are passed in fr5 and fr7
-   The rest are passed on the stack starting at SP-52, but 64-bit
-     arguments need to be aligned to an 8-byte boundary
+   The first four argument words on the stack are reserved for use by
+   the callee.  Instead, the general and floating registers replace
+   the first four argument slots.  Non FP arguments are passed solely
+   in the general registers.  FP arguments are passed in both general
+   and floating registers when using libffi.
+
+   Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23.
+   Non-FP 64-bit args are passed in register pairs, starting
+   on an odd numbered register (i.e. r25+r26 and r23+r24).
+   FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L.
+   FP 64-bit arguments are passed in fr5 and fr7.
+
+   The registers are allocated in the same manner as stack slots.
+   This allows the callee to save its arguments on the stack if
+   necessary:
+
+   arg word 3 -> gr23 or fr7L
+   arg word 2 -> gr24 or fr6L or fr7R
+   arg word 1 -> gr25 or fr5L
+   arg word 0 -> gr26 or fr4L or fr5R
+
+   Note that fr4R and fr6R are never used for arguments (i.e.,
+   doubles are not passed in fr4 or fr6).
+
+   The rest of the arguments are passed on the stack starting at SP-52,
+   but 64-bit arguments need to be aligned to an 8-byte boundary
   
    This means we can have holes either in the register allocation,
    or in the stack.  */
@@ -108,17 +135,17 @@
    NOTE: We load floating point args in this function... that means we
    assume gcc will not mess with fp regs in here.  */
 
-/address@hidden@*/
-void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes)
-/address@hidden@*/
+void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes)
 {
   register unsigned int i;
   register ffi_type **p_arg;
   register void **p_argv;
-  unsigned int slot = FIRST_ARG_SLOT - 1;
+  unsigned int slot = FIRST_ARG_SLOT;
   char *dest_cpy;
+  size_t len;
 
-  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack, 
ecif, bytes);
+  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
+       ecif, bytes);
 
   p_arg = ecif->cif->arg_types;
   p_argv = ecif->avalue;
@@ -130,116 +157,105 @@
       switch (type)
        {
        case FFI_TYPE_SINT8:
-         slot++;
          *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
          break;
 
        case FFI_TYPE_UINT8:
-         slot++;
          *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
          break;
 
        case FFI_TYPE_SINT16:
-         slot++;
          *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
          break;
 
        case FFI_TYPE_UINT16:
-         slot++;
          *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
          break;
 
        case FFI_TYPE_UINT32:
        case FFI_TYPE_SINT32:
        case FFI_TYPE_POINTER:
-         slot++;
-         debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv), 
slot);
+         debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv),
+               slot);
          *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
          break;
 
        case FFI_TYPE_UINT64:
        case FFI_TYPE_SINT64:
-         slot += 2;
-         if (slot & 1)
-           slot++;
-
-         *(UINT32 *)(stack - slot) = (*(UINT64 *)(*p_argv)) >> 32;
-         *(UINT32 *)(stack - slot + 1) = (*(UINT64 *)(*p_argv)) & 0xffffffffUL;
+         /* Align slot for 64-bit type.  */
+         slot += (slot & 1) ? 1 : 2;
+         *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
          break;
 
        case FFI_TYPE_FLOAT:
-         /* First 4 args go in fr4L - fr7L */
-         slot++;
-         switch (slot - FIRST_ARG_SLOT)
-           {
-           case 0: fldw(*p_argv, fr4); break;
-           case 1: fldw(*p_argv, fr5); break;
-           case 2: fldw(*p_argv, fr6); break;
-           case 3: fldw(*p_argv, fr7); break;
-           default:
-             /* Other ones are just passed on the stack.  */
+         /* First 4 args go in fr4L - fr7L.  */
              debug(3, "Storing UINT32(float) in slot %u\n", slot);
              *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
-             break;
+         switch (slot - FIRST_ARG_SLOT)
+           {
+           /* First 4 args go in fr4L - fr7L.  */
+           case 0: fldw(stack - slot, fr4); break;
+           case 1: fldw(stack - slot, fr5); break;
+           case 2: fldw(stack - slot, fr6); break;
+           case 3: fldw(stack - slot, fr7); break;
            }
            break;
 
        case FFI_TYPE_DOUBLE:
-         slot += 2;
-         if (slot & 1)
-           slot++;
-         switch (slot - FIRST_ARG_SLOT + 1)
-           {
-             /* First 2 args go in fr5, fr7 */
-             case 2: fldd(*p_argv, fr5); break;
-             case 4: fldd(*p_argv, fr7); break;
-             default:
+         /* Align slot for 64-bit type.  */
+         slot += (slot & 1) ? 1 : 2;
                debug(3, "Storing UINT64(double) at slot %u\n", slot);
                *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
-               break;
+         switch (slot - FIRST_ARG_SLOT)
+           {
+             /* First 2 args go in fr5, fr7.  */
+             case 1: fldd(stack - slot, fr5); break;
+             case 3: fldd(stack - slot, fr7); break;
            }
          break;
 
+#ifdef PA_HPUX
+       case FFI_TYPE_LONGDOUBLE:
+         /* Long doubles are passed in the same manner as structures
+            larger than 8 bytes.  */
+         *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
+         break;
+#endif
+
        case FFI_TYPE_STRUCT:
 
          /* Structs smaller or equal than 4 bytes are passed in one
             register. Structs smaller or equal 8 bytes are passed in two
             registers. Larger structures are passed by pointer.  */
 
-         if((*p_arg)->size <= 4) 
+         len = (*p_arg)->size;
+         if (len <= 4)
            {
-             slot++;
-             dest_cpy = (char *)(stack - slot);
-             dest_cpy += 4 - (*p_arg)->size;
-             memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
+             dest_cpy = (char *)(stack - slot) + 4 - len;
+             memcpy(dest_cpy, (char *)*p_argv, len);
            }
-         else if ((*p_arg)->size <= 8) 
+         else if (len <= 8)
            {
-             slot += 2;
-             if (slot & 1)
-               slot++;
-             dest_cpy = (char *)(stack - slot);
-             dest_cpy += 8 - (*p_arg)->size;
-             memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
+             slot += (slot & 1) ? 1 : 2;
+             dest_cpy = (char *)(stack - slot) + 8 - len;
+             memcpy(dest_cpy, (char *)*p_argv, len);
            } 
          else 
-           {
-             slot++;
              *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
-           }
          break;
 
        default:
          FFI_ASSERT(0);
        }
 
+      slot++;
       p_arg++;
       p_argv++;
     }
 
   /* Make sure we didn't mess up and scribble on the stack.  */
   {
-    int n;
+    unsigned int n;
 
     debug(5, "Stack setup:\n");
     for (n = 0; n < (bytes + 3) / 4; n++)
@@ -255,7 +271,7 @@
   return;
 }
 
-static void ffi_size_stack_LINUX(ffi_cif *cif)
+static void ffi_size_stack_pa32(ffi_cif *cif)
 {
   ffi_type **ptr;
   int i;
@@ -273,6 +289,9 @@
          z += 2 + (z & 1); /* must start on even regs, so we may waste one */
          break;
 
+#ifdef PA_HPUX
+       case FFI_TYPE_LONGDOUBLE:
+#endif
        case FFI_TYPE_STRUCT:
          z += 1; /* pass by ptr, callee will copy */
          break;
@@ -304,6 +323,13 @@
       cif->flags = (unsigned) cif->rtype->type;
       break;
 
+#ifdef PA_HPUX
+    case FFI_TYPE_LONGDOUBLE:
+      /* Long doubles are treated like a structure.  */
+      cif->flags = FFI_TYPE_STRUCT;
+      break;
+#endif
+
     case FFI_TYPE_STRUCT:
       /* For the return type we have to check the size of the structures.
         If the size is smaller or equal 4 bytes, the result is given back
@@ -327,8 +353,8 @@
      own stack sizing.  */
   switch (cif->abi)
     {
-    case FFI_LINUX:
-      ffi_size_stack_LINUX(cif);
+    case FFI_PA32:
+      ffi_size_stack_pa32(cif);
       break;
 
     default:
@@ -339,20 +365,11 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned),
-                          /address@hidden@*/ extended_cif *,
-                          unsigned, unsigned,
-                          /address@hidden@*/ unsigned *,
+extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
+                         extended_cif *, unsigned, unsigned, unsigned *,
                           void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif,
-             void (*fn)(),
-             /address@hidden@*/ void *rvalue,
-             /address@hidden@*/ void **avalue)
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -362,12 +379,15 @@
   /* 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))
+  if (rvalue == NULL
+#ifdef PA_HPUX
+      && (cif->rtype->type == FFI_TYPE_STRUCT
+         || cif->rtype->type == FFI_TYPE_LONGDOUBLE))
+#else
+      && cif->rtype->type == FFI_TYPE_STRUCT)
+#endif
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -375,12 +395,10 @@
 
   switch (cif->abi)
     {
-    case FFI_LINUX:
-      /address@hidden@*/
-      debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, 
rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
-      ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes,
+    case FFI_PA32:
+      debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, 
fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
+      ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes,
                     cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
       break;
 
     default:
@@ -394,7 +412,7 @@
    the stack, and we need to fill them into a cif structure and invoke
    the user function. This really ought to be in asm to make sure
    the compiler doesn't do things we don't expect.  */
-UINT32 ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack)
+ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
 {
   ffi_cif *cif;
   void **avalue;
@@ -402,7 +420,8 @@
   UINT32 ret[2]; /* function can return up to 64-bits in registers */
   ffi_type **p_arg;
   char *tmp;
-  int i, avn, slot = FIRST_ARG_SLOT - 1;
+  int i, avn;
+  unsigned int slot = FIRST_ARG_SLOT;
   register UINT32 r28 asm("r28");
 
   cif = closure->cif;
@@ -430,20 +449,23 @@
        case FFI_TYPE_SINT32:
        case FFI_TYPE_UINT32:
        case FFI_TYPE_POINTER:
-         slot++;
          avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
          break;
 
        case FFI_TYPE_SINT64:
        case FFI_TYPE_UINT64:
-         slot += 2;
-         if (slot & 1)
-           slot++;
+         slot += (slot & 1) ? 1 : 2;
          avalue[i] = (void *)(stack - slot);
          break;
 
        case FFI_TYPE_FLOAT:
-         slot++;
+#ifdef PA_LINUX
+         /* The closure call is indirect.  In Linux, floating point
+            arguments in indirect calls with a prototype are passed
+            in the floating point registers instead of the general
+            registers.  So, we need to replace what was previously
+            stored in the current slot with the value in the
+            corresponding floating point register.  */
          switch (slot - FIRST_ARG_SLOT)
            {
            case 0: fstw(fr4, (void *)(stack - slot)); break;
@@ -451,18 +473,20 @@
            case 2: fstw(fr6, (void *)(stack - slot)); break;
            case 3: fstw(fr7, (void *)(stack - slot)); break;
            }
+#endif
          avalue[i] = (void *)(stack - slot);
          break;
 
        case FFI_TYPE_DOUBLE:
-         slot += 2;
-         if (slot & 1)
-           slot++;
-         switch (slot - FIRST_ARG_SLOT + 1)
+         slot += (slot & 1) ? 1 : 2;
+#ifdef PA_LINUX
+         /* See previous comment for FFI_TYPE_FLOAT.  */
+         switch (slot - FIRST_ARG_SLOT)
            {
-           case 2: fstd(fr5, (void *)(stack - slot)); break;
-           case 4: fstd(fr7, (void *)(stack - slot)); break;
+           case 1: fstd(fr5, (void *)(stack - slot)); break;
+           case 3: fstd(fr7, (void *)(stack - slot)); break;
            }
+#endif
          avalue[i] = (void *)(stack - slot);
          break;
 
@@ -470,35 +494,36 @@
          /* Structs smaller or equal than 4 bytes are passed in one
             register. Structs smaller or equal 8 bytes are passed in two
             registers. Larger structures are passed by pointer.  */
-         if((*p_arg)->size <= 4) {
-           slot++;
+         if((*p_arg)->size <= 4)
+           {
            avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
              (*p_arg)->size;
-         } else if ((*p_arg)->size <= 8) {
-           slot += 2;
-           if (slot & 1)
-             slot++;
+           }
+         else if ((*p_arg)->size <= 8)
+           {
+             slot += (slot & 1) ? 1 : 2;
            avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
              (*p_arg)->size;
-         } else {
-           slot++;
-           avalue[i] = (void *) *(stack - slot);
          }
+         else
+           avalue[i] = (void *) *(stack - slot);
          break;
 
        default:
          FFI_ASSERT(0);
        }
 
+      slot++;
       p_arg++;
     }
 
   /* Invoke the closure.  */
   (closure->fun) (cif, rvalue, avalue, closure->user_data);
 
-  debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], 
ret[1]);
+  debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
+       ret[1]);
 
-  /* Store the result */
+  /* Store the result using the lower 2 bytes of the flags.  */
   switch (cif->flags)
     {
     case FFI_TYPE_UINT8:
@@ -536,7 +561,9 @@
       /* Don't need a return value, done by caller.  */
       break;
 
+    case FFI_TYPE_SMALL_STRUCT2:
     case FFI_TYPE_SMALL_STRUCT3:
+    case FFI_TYPE_SMALL_STRUCT4:
       tmp = (void*)(stack -  FIRST_ARG_SLOT);
       tmp += 4 - cif->rtype->size;
       memcpy((void*)tmp, &ret[0], cif->rtype->size);
@@ -545,6 +572,7 @@
     case FFI_TYPE_SMALL_STRUCT5:
     case FFI_TYPE_SMALL_STRUCT6:
     case FFI_TYPE_SMALL_STRUCT7:
+    case FFI_TYPE_SMALL_STRUCT8:
       {
        unsigned int ret2[2];
        int off;
@@ -582,39 +610,93 @@
    cif specifies the argument and result types for fun.
    The cif must already be prep'ed.  */
 
-void ffi_closure_LINUX(void);
+extern void ffi_closure_pa32(void);
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*,void*,void**,void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   UINT32 *tramp = (UINT32 *)(closure->tramp);
+#ifdef PA_HPUX
+  UINT32 *tmp;
+#endif
 
-  FFI_ASSERT (cif->abi == FFI_LINUX);
+  FFI_ASSERT (cif->abi == FFI_PA32);
 
   /* Make a small trampoline that will branch to our
      handler function. Use PC-relative addressing.  */
 
-  tramp[0] = 0xeaa00000; /* b,l  .+8, %r21      ; %r21 <- pc+8 */
-  tramp[1] = 0xd6a01c1e; /* depi 0,31,2, %r21   ; mask priv bits */
-  tramp[2] = 0x4aa10028; /* ldw  20(%r21), %r1  ; load plabel */
-  tramp[3] = 0x36b53ff1; /* ldo  -8(%r21), %r21 ; get closure addr */
-  tramp[4] = 0x0c201096; /* ldw  0(%r1), %r22   ; address of handler */
-  tramp[5] = 0xeac0c000; /* bv  %r0(%r22)      ; branch to handler */
-  tramp[6] = 0x0c281093; /* ldw  4(%r1), %r19   ; GP of handler */
-  tramp[7] = ((UINT32)(ffi_closure_LINUX) & ~2);
+#ifdef PA_LINUX
+  tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8 */
+  tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits */
+  tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1    ; load plabel */
+  tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr */
+  tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler */
+  tramp[5] = 0xeac0c000; /* bv%r0(%r22)         ; branch to handler */
+  tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler */
+  tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
 
   /* Flush d/icache -- have to flush up 2 two lines because of
      alignment.  */
-  asm volatile (
-               "fdc 0(%0)\n"
-               "fdc %1(%0)\n"
-               "fic 0(%%sr4, %0)\n"
-               "fic %1(%%sr4, %0)\n"
-               "sync\n"
-               : : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */));
+  __asm__ volatile(
+                  "fdc 0(%0)\n\t"
+                  "fdc %1(%0)\n\t"
+                  "fic 0(%%sr4, %0)\n\t"
+                  "fic %1(%%sr4, %0)\n\t"
+                  "sync\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n"
+                  :
+                  : "r"((unsigned long)tramp & ~31),
+                    "r"(32 /* stride */)
+                  : "memory");
+#endif
+
+#ifdef PA_HPUX
+  tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8  */
+  tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits  */
+  tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1    ; load plabel  */
+  tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr  */
+  tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler  */
+  tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20   ; load space id  */
+  tramp[6] = 0x00141820; /* mtsp %r20,%sr0      ; into %sr0  */
+  tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22)     ; branch to handler  */
+  tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler  */
+  tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
+
+  /* Flush d/icache -- have to flush three lines because of alignment.  */
+  __asm__ volatile(
+                  "copy %1,%0\n\t"
+                  "fdc,m %2(%0)\n\t"
+                  "fdc,m %2(%0)\n\t"
+                  "fdc,m %2(%0)\n\t"
+                  "ldsid (%1),%0\n\t"
+                  "mtsp %0,%%sr0\n\t"
+                  "copy %1,%0\n\t"
+                  "fic,m %2(%%sr0,%0)\n\t"
+                  "fic,m %2(%%sr0,%0)\n\t"
+                  "fic,m %2(%%sr0,%0)\n\t"
+                  "sync\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n\t"
+                  "nop\n"
+                  : "=&r" ((unsigned long)tmp)
+                  : "r" ((unsigned long)tramp & ~31),
+                    "r" (32/* stride */)
+                  : "memory");
+#endif
 
   closure->cif  = cif;
   closure->user_data = user_data;

Index: libffi/src/pa/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/pa/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/pa/ffitarget.h   30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/pa/ffitarget.h   30 Nov 2007 20:59:56 -0000      1.2
@@ -35,9 +35,20 @@
 typedef enum ffi_abi {
   FFI_FIRST_ABI = 0,
 
-#ifdef PA
-  FFI_LINUX,
-  FFI_DEFAULT_ABI = FFI_LINUX,
+#ifdef PA_LINUX
+  FFI_PA32,
+  FFI_DEFAULT_ABI = FFI_PA32,
+#endif
+
+#ifdef PA_HPUX
+  FFI_PA32,
+  FFI_DEFAULT_ABI = FFI_PA32,
+#endif
+
+#ifdef PA64_HPUX
+#error "PA64_HPUX FFI is not yet implemented"
+  FFI_PA64,
+  FFI_DEFAULT_ABI = FFI_PA64,
 #endif
 
   FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
@@ -49,11 +60,17 @@
 #define FFI_CLOSURES 1
 #define FFI_NATIVE_RAW_API 0
 
+#ifdef PA_LINUX
 #define FFI_TRAMPOLINE_SIZE 32
-
-#define FFI_TYPE_SMALL_STRUCT3 -1
-#define FFI_TYPE_SMALL_STRUCT5 -2
-#define FFI_TYPE_SMALL_STRUCT6 -3
-#define FFI_TYPE_SMALL_STRUCT7 -4
+#else
+#define FFI_TRAMPOLINE_SIZE 40
 #endif
 
+#define FFI_TYPE_SMALL_STRUCT2 -1
+#define FFI_TYPE_SMALL_STRUCT3 -2
+#define FFI_TYPE_SMALL_STRUCT4 -3
+#define FFI_TYPE_SMALL_STRUCT5 -4
+#define FFI_TYPE_SMALL_STRUCT6 -5
+#define FFI_TYPE_SMALL_STRUCT7 -6
+#define FFI_TYPE_SMALL_STRUCT8 -7
+#endif

Index: libffi/src/pa/linux.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/pa/linux.S,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/pa/linux.S       30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/pa/linux.S       30 Nov 2007 20:59:57 -0000      1.2
@@ -31,7 +31,7 @@
        .level 1.1
        .align 4
 
-       /* void ffi_call_LINUX(void (*)(char *, extended_cif *),
+       /* void ffi_call_pa32(void (*)(char *, extended_cif *),
                               extended_cif *ecif,
                               unsigned bytes,
                               unsigned flags,
@@ -39,12 +39,12 @@
                               void (*fn)());
         */
 
-       .export ffi_call_LINUX,code
-       .import ffi_prep_args_LINUX,code
+       .export ffi_call_pa32,code
+       .import ffi_prep_args_pa32,code
 
-       .type ffi_call_LINUX, @function
+       .type ffi_call_pa32, @function
 .LFB1:
-ffi_call_LINUX:
+ffi_call_pa32:
        .proc
        .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
        .entry
@@ -63,7 +63,7 @@
           [ 64-bytes register save area               ] <- %r4
 
           [ Stack space for actual call, passed as    ] <- %arg0
-          [     arg0 to ffi_prep_args_LINUX           ]
+          [     arg0 to ffi_prep_args_pa32           ]
 
           [ Stack for calling prep_args               ] <- %sp
         */
@@ -80,7 +80,7 @@
           %arg0(stack) -- set up above
           %arg1(ecif) -- same as incoming param
           %arg2(bytes) -- same as incoming param */
-       bl ffi_prep_args_LINUX,%r2
+       bl ffi_prep_args_pa32,%r2
        ldo 64(%arg0), %sp
        ldo -64(%sp), %sp
 
@@ -106,90 +106,139 @@
 
        /* Store the result according to the return type.  */
 
-checksmst3:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, checksmst567
-       /* 3-byte structs are returned in ret0 as ??xxyyzz.  Shift
-          left 8 bits to write to the result structure.  */
-       zdep %ret0, 23, 24, %r22
-       b done
-       stw %r22, 0(%r20)
-
-checksmst567:
-       /* 5-7 byte values are returned right justified:
-             ret0     ret1
-          5: ??????aa bbccddee
-          6: ????aabb ccddeeff
-          7: ??aabbcc ddeeffgg
-
-          To store this in the result, write the first 4 bytes into a temp
-          register using shrpw (t1 = aabbccdd), followed by a rotation of
-          ret1:
-
-             ret0     ret1        ret1
-          5: ??????aa bbccddee -> eebbccdd (rotate 8)
-          6: ????aabb ccddeeff -> eeffccdd (rotate 16)
-          7: ??aabbcc ddeeffgg -> eeffggdd (rotate 24)
-
-          then we write (t1, ret1) into the result.  */
-
-       addi,<> -FFI_TYPE_SMALL_STRUCT5,%r21,%r0
-       ldi 8, %r22
-       addi,<> -FFI_TYPE_SMALL_STRUCT6,%r21,%r0
-       ldi 16, %r22
-       addi,<> -FFI_TYPE_SMALL_STRUCT7,%r21,%r0
-       ldi 24, %r22
-
-       /* This relies on all the FFI_TYPE_*_STRUCT* defines being <0 */
-       cmpib,<=,n 0, %r21, checkint8
-       mtsar %r22
-
-       shrpw %ret0, %ret1, %sar, %ret0  /* ret0 = aabbccdd */
-       shrpw %ret1, %ret1, %sar, %ret1  /* rotate ret1 */
-       
+.Lcheckint:
+       comib,<>,n FFI_TYPE_INT, %r21, .Lcheckint8
+       b       .Ldone
        stw %ret0, 0(%r20)
-       b done
-       stw %ret1, 4(%r20)
 
-checkint8:
-       comib,<>,n FFI_TYPE_UINT8, %r21, checkint16
-       b done
+.Lcheckint8:
+       comib,<>,n FFI_TYPE_UINT8, %r21, .Lcheckint16
+       b       .Ldone
        stb %ret0, 0(%r20)
 
-checkint16:
-       comib,<>,n FFI_TYPE_UINT16, %r21, checkint32
-       b done
+.Lcheckint16:
+       comib,<>,n FFI_TYPE_UINT16, %r21, .Lcheckdbl
+       b       .Ldone
        sth %ret0, 0(%r20)
 
-checkint32:
-       comib,<>,n FFI_TYPE_UINT32, %r21, checkint
-       b done
-       stw %ret0, 0(%r20)
+.Lcheckdbl:
+       comib,<>,n FFI_TYPE_DOUBLE, %r21, .Lcheckfloat
+       b       .Ldone
+       fstd    %fr4,0(%r20)
 
-checkint:
-       comib,<>,n FFI_TYPE_INT, %r21, checkll
-       b done
-       stw %ret0, 0(%r20)
+.Lcheckfloat:
+       comib,<>,n FFI_TYPE_FLOAT, %r21, .Lcheckll
+       b       .Ldone
+       fstw    %fr4L,0(%r20)
 
-checkll:
-       comib,<>,n FFI_TYPE_UINT64, %r21, checkdbl
+.Lcheckll:
+       comib,<>,n FFI_TYPE_UINT64, %r21, .Lchecksmst2
        stw %ret0, 0(%r20)
-       b done
+       b       .Ldone
        stw %ret1, 4(%r20)
 
-checkdbl:
-       comib,<>,n FFI_TYPE_DOUBLE, %r21, checkfloat
-       b done
-       fstd %fr4,0(%r20)
+.Lchecksmst2:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, .Lchecksmst3
+       /* 2-byte structs are returned in ret0 as ????xxyy.  */
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret0, 0(%r20)
 
-checkfloat:
-       comib,<>,n FFI_TYPE_FLOAT, %r21, done
-       fstw %fr4L,0(%r20)
+.Lchecksmst3:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, .Lchecksmst4
+       /* 3-byte structs are returned in ret0 as ??xxyyzz.  */
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret0, 0(%r20)
+
+.Lchecksmst4:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, .Lchecksmst5
+       /* 4-byte structs are returned in ret0 as wwxxyyzz.  */
+       extru   %ret0, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret0, 0(%r20)
 
-       /* structure returns are either handled by one of the
-          INT/UINT64 cases above, or, if passed by pointer,
-          is handled by the callee.  */
+.Lchecksmst5:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, .Lchecksmst6
+       /* 5 byte values are returned right justified:
+             ret0     ret1
+          5: ??????aa bbccddee */
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret1, 0(%r20)
+
+.Lchecksmst6:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, .Lchecksmst7
+       /* 6 byte values are returned right justified:
+             ret0     ret1
+          6: ????aabb ccddeeff */
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret1, 0(%r20)
+
+.Lchecksmst7:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, .Lchecksmst8
+       /* 7 byte values are returned right justified:
+             ret0     ret1
+          7: ??aabbcc ddeeffgg */
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       .Ldone
+       stb     %ret1, 0(%r20)
+
+.Lchecksmst8:
+       comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, .Ldone
+       /* 8 byte values are returned right justified:
+             ret0     ret1
+          8: aabbccdd eeffgghh */
+       extru   %ret0, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stb     %ret1, 0(%r20)
 
-done:
+.Ldone:
        /* all done, return */
        copy %r4, %sp                           /* pop arg stack */
        ldw 12(%r3), %r4
@@ -201,14 +250,14 @@
        .procend
 .LFE1:
 
-       /* void ffi_closure_LINUX(void);
+       /* void ffi_closure_pa32(void);
           Called with closure argument in %r21 */
-       .export ffi_closure_LINUX,code
-       .import ffi_closure_inner_LINUX,code
+       .export ffi_closure_pa32,code
+       .import ffi_closure_inner_pa32,code
 
-       .type ffi_closure_LINUX, @function
+       .type ffi_closure_pa32, @function
 .LFB2:
-ffi_closure_LINUX:
+ffi_closure_pa32:
        .proc
        .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
        .entry
@@ -228,7 +277,7 @@
        stw %arg3, -48(%r3)
 
        copy %r21, %arg0
-       bl ffi_closure_inner_LINUX, %r2
+       bl ffi_closure_inner_pa32, %r2
        copy %r3, %arg1
 
        ldwm -64(%sp), %r3
@@ -299,7 +348,7 @@
        .sleb128 -5
 
        .byte   0x4     ;# DW_CFA_advance_loc4
-       .word   .LCFI12-.LCFI11
+       .word   .LCFI22-.LCFI21
        .byte   0xd     ;# DW_CFA_def_cfa_register = r3
        .uleb128 0x3
 

Index: libffi/src/powerpc/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/ffi.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libffi/src/powerpc/ffi.c    19 Dec 2005 07:07:56 -0000      1.6
+++ libffi/src/powerpc/ffi.c    30 Nov 2007 20:59:57 -0000      1.7
@@ -1,5 +1,6 @@
 /* -----------------------------------------------------------------------
    ffi.c - Copyright (c) 1998 Geoffrey Keating
+   Copyright (C) 2007 Free Software Foundation, Inc
 
    PowerPC Foreign Function Interface
 
@@ -30,8 +31,8 @@
 #include <stdio.h>
 
 
-extern void ffi_closure_SYSV(void);
-extern void FFI_HIDDEN ffi_closure_LINUX64(void);
+extern void ffi_closure_SYSV (void);
+extern void FFI_HIDDEN ffi_closure_LINUX64 (void);
 
 enum {
   /* The assembly depends on these exact flags.  */
@@ -39,7 +40,8 @@
   FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7 */
   FLAG_RETURNS_FP       = 1 << (31-29),
   FLAG_RETURNS_64BITS   = 1 << (31-28),
-  FLAG_RETURNS_128BITS  = 1 << (31-27),
+
+  FLAG_RETURNS_128BITS  = 1 << (31-27), /* cr6  */
 
   FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
   FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
@@ -80,79 +82,103 @@
 
 */
 
-/address@hidden@*/
-void ffi_prep_args_SYSV(extended_cif *ecif, unsigned *const stack)
-/address@hidden@*/
+void
+ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
 {
   const unsigned bytes = ecif->cif->bytes;
   const unsigned flags = ecif->cif->flags;
 
+  typedef union {
+    char *c;
+    unsigned *u;
+    long long *ll;
+    float *f;
+    double *d;
+  } valp;
+
   /* 'stacktop' points at the previous backchain pointer.  */
-  unsigned *const stacktop = stack + (bytes / sizeof(unsigned));
+  valp stacktop;
 
   /* 'gpr_base' points at the space for gpr3, and grows upwards as
      we use GPR registers.  */
-  unsigned *gpr_base = stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
-  int intarg_count = 0;
+  valp gpr_base;
+  int intarg_count;
 
   /* 'fpr_base' points at the space for fpr1, and grows upwards as
      we use FPR registers.  */
-  double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS;
-  int fparg_count = 0;
+  valp fpr_base;
+  int fparg_count;
 
   /* 'copy_space' grows down as we put structures in it.  It should
      stay 16-byte aligned.  */
-  char *copy_space = ((flags & FLAG_FP_ARGUMENTS)
-                     ? (char *)fpr_base
-                     : (char *)gpr_base);
+  valp copy_space;
 
   /* 'next_arg' grows up as we put parameters in it.  */
-  unsigned *next_arg = stack + 2;
+  valp next_arg;
 
   int i;
   ffi_type **ptr;
   double double_tmp;
-  void **p_argv;
+  union {
+    void **v;
+    char **c;
+    signed char **sc;
+    unsigned char **uc;
+    signed short **ss;
+    unsigned short **us;
+    unsigned int **ui;
+    long long **ll;
+    float **f;
+    double **d;
+  } p_argv;
   size_t struct_copy_size;
   unsigned gprvalue;
 
+  stacktop.c = (char *) stack + bytes;
+  gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
+  intarg_count = 0;
+  fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
+  fparg_count = 0;
+  copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
+  next_arg.u = stack + 2;
+
   /* Check that everything starts aligned properly.  */
-  FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
-  FFI_ASSERT(((unsigned)(char *)copy_space & 0xF) == 0);
-  FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
-  FFI_ASSERT((bytes & 0xF) == 0);
-  FFI_ASSERT(copy_space >= (char *)next_arg);
+  FFI_ASSERT (((unsigned) (char *) stack & 0xF) == 0);
+  FFI_ASSERT (((unsigned) copy_space.c & 0xF) == 0);
+  FFI_ASSERT (((unsigned) stacktop.c & 0xF) == 0);
+  FFI_ASSERT ((bytes & 0xF) == 0);
+  FFI_ASSERT (copy_space.c >= next_arg.c);
 
   /* Deal with return values that are actually pass-by-reference.  */
   if (flags & FLAG_RETVAL_REFERENCE)
     {
-      *gpr_base++ = (unsigned long)(char *)ecif->rvalue;
+      *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue;
       intarg_count++;
     }
 
   /* Now for the arguments.  */
-  p_argv = ecif->avalue;
+  p_argv.v = ecif->avalue;
   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
        i > 0;
-       i--, ptr++, p_argv++)
+       i--, ptr++, p_argv.v++)
     {
       switch ((*ptr)->type)
        {
        case FFI_TYPE_FLOAT:
-         double_tmp = *(float *)*p_argv;
+         double_tmp = **p_argv.f;
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
            {
-             *(float *)next_arg = (float)double_tmp;
-             next_arg += 1;
+             *next_arg.f = (float) double_tmp;
+             next_arg.u += 1;
            }
          else
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 
        case FFI_TYPE_DOUBLE:
-         double_tmp = *(double *)*p_argv;
+         double_tmp = **p_argv.d;
 
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
            {
@@ -160,16 +186,48 @@
                  && intarg_count % 2 != 0)
                {
                  intarg_count++;
-                 next_arg++;
+                 next_arg.u++;
                }
-             *(double *)next_arg = double_tmp;
-             next_arg += 2;
+             *next_arg.d = double_tmp;
+             next_arg.u += 2;
            }
          else
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+         break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       case FFI_TYPE_LONGDOUBLE:
+         if (ecif->cif->abi != FFI_LINUX)
+           goto do_struct;
+         double_tmp = (*p_argv.d)[0];
+
+         if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
+           {
+             if (intarg_count >= NUM_GPR_ARG_REGISTERS
+                 && intarg_count % 2 != 0)
+               {
+                 intarg_count++;
+                 next_arg.u++;
+               }
+             *next_arg.d = double_tmp;
+             next_arg.u += 2;
+             double_tmp = (*p_argv.d)[1];
+             *next_arg.d = double_tmp;
+             next_arg.u += 2;
+           }
+         else
+           {
+             *fpr_base.d++ = double_tmp;
+             double_tmp = (*p_argv.d)[1];
+             *fpr_base.d++ = double_tmp;
+           }
+
+         fparg_count += 2;
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
+#endif
 
        case FFI_TYPE_UINT64:
        case FFI_TYPE_SINT64:
@@ -177,13 +235,13 @@
            intarg_count++;
          if (intarg_count >= NUM_GPR_ARG_REGISTERS)
            {
-             if (intarg_count%2 != 0)
+             if (intarg_count % 2 != 0)
                {
                  intarg_count++;
-                 next_arg++;
+                 next_arg.u++;
                }
-             *(long long *)next_arg = *(long long *)*p_argv;
-             next_arg += 2;
+             *next_arg.ll = **p_argv.ll;
+             next_arg.u += 2;
            }
          else
            {
@@ -194,65 +252,65 @@
               * not correct starting register of pair then skip
               * until the proper starting register
               */
-             if (intarg_count%2 != 0)
+             if (intarg_count % 2 != 0)
                {
                  intarg_count ++;
-                 gpr_base++;
+                 gpr_base.u++;
                }
-             *(long long *)gpr_base = *(long long *)*p_argv;
-             gpr_base += 2;
+             *gpr_base.ll++ = **p_argv.ll;
            }
          intarg_count += 2;
          break;
 
        case FFI_TYPE_STRUCT:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-       case FFI_TYPE_LONGDOUBLE:
+       do_struct:
 #endif
          struct_copy_size = ((*ptr)->size + 15) & ~0xF;
-         copy_space -= struct_copy_size;
-         memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
+         copy_space.c -= struct_copy_size;
+         memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
 
-         gprvalue = (unsigned long)copy_space;
+         gprvalue = (unsigned long) copy_space.c;
 
-         FFI_ASSERT(copy_space > (char *)next_arg);
-         FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
+         FFI_ASSERT (copy_space.c > next_arg.c);
+         FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY);
          goto putgpr;
 
        case FFI_TYPE_UINT8:
-         gprvalue = *(unsigned char *)*p_argv;
+         gprvalue = **p_argv.uc;
          goto putgpr;
        case FFI_TYPE_SINT8:
-         gprvalue = *(signed char *)*p_argv;
+         gprvalue = **p_argv.sc;
          goto putgpr;
        case FFI_TYPE_UINT16:
-         gprvalue = *(unsigned short *)*p_argv;
+         gprvalue = **p_argv.us;
          goto putgpr;
        case FFI_TYPE_SINT16:
-         gprvalue = *(signed short *)*p_argv;
+         gprvalue = **p_argv.ss;
          goto putgpr;
 
        case FFI_TYPE_INT:
        case FFI_TYPE_UINT32:
        case FFI_TYPE_SINT32:
        case FFI_TYPE_POINTER:
-         gprvalue = *(unsigned *)*p_argv;
+         gprvalue = **p_argv.ui;
+
        putgpr:
          if (intarg_count >= NUM_GPR_ARG_REGISTERS)
-           *next_arg++ = gprvalue;
+           *next_arg.u++ = gprvalue;
          else
-           *gpr_base++ = gprvalue;
+           *gpr_base.u++ = gprvalue;
          intarg_count++;
          break;
        }
     }
 
   /* Check that we didn't overrun the stack...  */
-  FFI_ASSERT(copy_space >= (char *)next_arg);
-  FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
-  FFI_ASSERT((unsigned *)fpr_base
-            <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
-  FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
+  FFI_ASSERT (copy_space.c >= next_arg.c);
+  FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
+  FFI_ASSERT (fpr_base.u
+             <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
+  FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
 }
 
 /* About the LINUX64 ABI.  */
@@ -296,160 +354,187 @@
 
 */
 
-/address@hidden@*/
-void FFI_HIDDEN ffi_prep_args64(extended_cif *ecif, unsigned long *const stack)
-/address@hidden@*/
+void FFI_HIDDEN
+ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
 {
   const unsigned long bytes = ecif->cif->bytes;
   const unsigned long flags = ecif->cif->flags;
 
+  typedef union {
+    char *c;
+    unsigned long *ul;
+    float *f;
+    double *d;
+  } valp;
+
   /* 'stacktop' points at the previous backchain pointer.  */
-  unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long));
+  valp stacktop;
 
   /* 'next_arg' points at the space for gpr3, and grows upwards as
      we use GPR registers, then continues at rest.  */
-  unsigned long *const gpr_base = stacktop - ASM_NEEDS_REGISTERS64
-    - NUM_GPR_ARG_REGISTERS64;
-  unsigned long *const gpr_end = gpr_base + NUM_GPR_ARG_REGISTERS64;
-  unsigned long *const rest = stack + 6 + NUM_GPR_ARG_REGISTERS64;
-  unsigned long *next_arg = gpr_base;
+  valp gpr_base;
+  valp gpr_end;
+  valp rest;
+  valp next_arg;
 
   /* 'fpr_base' points at the space for fpr3, and grows upwards as
      we use FPR registers.  */
-  double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS64;
-  int fparg_count = 0;
+  valp fpr_base;
+  int fparg_count;
 
   int i, words;
   ffi_type **ptr;
   double double_tmp;
-  void **p_argv;
+  union {
+    void **v;
+    char **c;
+    signed char **sc;
+    unsigned char **uc;
+    signed short **ss;
+    unsigned short **us;
+    signed int **si;
+    unsigned int **ui;
+    unsigned long **ul;
+    float **f;
+    double **d;
+  } p_argv;
   unsigned long gprvalue;
 
+  stacktop.c = (char *) stack + bytes;
+  gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
+  gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
+  rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+  fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
+  fparg_count = 0;
+  next_arg.ul = gpr_base.ul;
+
   /* Check that everything starts aligned properly.  */
-  FFI_ASSERT(((unsigned long)(char *)stack & 0xF) == 0);
-  FFI_ASSERT(((unsigned long)(char *)stacktop & 0xF) == 0);
-  FFI_ASSERT((bytes & 0xF) == 0);
+  FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
+  FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
+  FFI_ASSERT ((bytes & 0xF) == 0);
 
   /* Deal with return values that are actually pass-by-reference.  */
   if (flags & FLAG_RETVAL_REFERENCE)
-    *next_arg++ = (unsigned long)(char *)ecif->rvalue;
+    *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
 
   /* Now for the arguments.  */
-  p_argv = ecif->avalue;
+  p_argv.v = ecif->avalue;
   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
        i > 0;
-       i--, ptr++, p_argv++)
+       i--, ptr++, p_argv.v++)
     {
       switch ((*ptr)->type)
        {
        case FFI_TYPE_FLOAT:
-         double_tmp = *(float *)*p_argv;
-         *(float *)next_arg = (float)double_tmp;
-         if (++next_arg == gpr_end)
-           next_arg = rest;
+         double_tmp = **p_argv.f;
+         *next_arg.f = (float) double_tmp;
+         if (++next_arg.ul == gpr_end.ul)
+           next_arg.ul = rest.ul;
          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 
        case FFI_TYPE_DOUBLE:
-         double_tmp = *(double *)*p_argv;
-         *(double *)next_arg = double_tmp;
-         if (++next_arg == gpr_end)
-           next_arg = rest;
+         double_tmp = **p_argv.d;
+         *next_arg.d = double_tmp;
+         if (++next_arg.ul == gpr_end.ul)
+           next_arg.ul = rest.ul;
          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
        case FFI_TYPE_LONGDOUBLE:
-         double_tmp = ((double *) *p_argv)[0];
-         *(double *) next_arg = double_tmp;
-         if (++next_arg == gpr_end)
-           next_arg = rest;
+         double_tmp = (*p_argv.d)[0];
+         *next_arg.d = double_tmp;
+         if (++next_arg.ul == gpr_end.ul)
+           next_arg.ul = rest.ul;
          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         double_tmp = ((double *) *p_argv)[1];
-         *(double *) next_arg = double_tmp;
-         if (++next_arg == gpr_end)
-           next_arg = rest;
+         double_tmp = (*p_argv.d)[1];
+         *next_arg.d = double_tmp;
+         if (++next_arg.ul == gpr_end.ul)
+           next_arg.ul = rest.ul;
          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
-           *fpr_base++ = double_tmp;
+           *fpr_base.d++ = double_tmp;
          fparg_count++;
-         FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+         FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 #endif
 
        case FFI_TYPE_STRUCT:
          words = ((*ptr)->size + 7) / 8;
-         if (next_arg >= gpr_base && next_arg + words > gpr_end)
+         if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
            {
-             size_t first = (char *) gpr_end - (char *) next_arg;
-             memcpy((char *) next_arg, (char *) *p_argv, first);
-             memcpy((char *) rest, (char *) *p_argv + first,
-                    (*ptr)->size - first);
-             next_arg = (unsigned long *) ((char *) rest + words * 8 - first);
+             size_t first = gpr_end.c - next_arg.c;
+             memcpy (next_arg.c, *p_argv.c, first);
+             memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
+             next_arg.c = rest.c + words * 8 - first;
            }
          else
            {
-             char *where = (char *) next_arg;
+             char *where = next_arg.c;
 
              /* Structures with size less than eight bytes are passed
                 left-padded.  */
              if ((*ptr)->size < 8)
                where += 8 - (*ptr)->size;
 
-             memcpy (where, (char *) *p_argv, (*ptr)->size);
-             next_arg += words;
-             if (next_arg == gpr_end)
-               next_arg = rest;
+             memcpy (where, *p_argv.c, (*ptr)->size);
+             next_arg.ul += words;
+             if (next_arg.ul == gpr_end.ul)
+               next_arg.ul = rest.ul;
            }
          break;
 
        case FFI_TYPE_UINT8:
-         gprvalue = *(unsigned char *)*p_argv;
+         gprvalue = **p_argv.uc;
          goto putgpr;
        case FFI_TYPE_SINT8:
-         gprvalue = *(signed char *)*p_argv;
+         gprvalue = **p_argv.sc;
          goto putgpr;
        case FFI_TYPE_UINT16:
-         gprvalue = *(unsigned short *)*p_argv;
+         gprvalue = **p_argv.us;
          goto putgpr;
        case FFI_TYPE_SINT16:
-         gprvalue = *(signed short *)*p_argv;
+         gprvalue = **p_argv.ss;
          goto putgpr;
        case FFI_TYPE_UINT32:
-         gprvalue = *(unsigned int *)*p_argv;
+         gprvalue = **p_argv.ui;
          goto putgpr;
        case FFI_TYPE_INT:
        case FFI_TYPE_SINT32:
-         gprvalue = *(signed int *)*p_argv;
+         gprvalue = **p_argv.si;
          goto putgpr;
 
        case FFI_TYPE_UINT64:
        case FFI_TYPE_SINT64:
        case FFI_TYPE_POINTER:
-         gprvalue = *(unsigned long *)*p_argv;
+         gprvalue = **p_argv.ul;
        putgpr:
-         *next_arg++ = gprvalue;
-         if (next_arg == gpr_end)
-           next_arg = rest;
+         *next_arg.ul++ = gprvalue;
+         if (next_arg.ul == gpr_end.ul)
+           next_arg.ul = rest.ul;
          break;
        }
     }
 
-  FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS
-            || (next_arg >= gpr_base && next_arg <= gpr_base + 4));
+  FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
+             || (next_arg.ul >= gpr_base.ul
+                 && next_arg.ul <= gpr_base.ul + 4));
 }
 
 
 
 /* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_status
+ffi_prep_cif_machdep (ffi_cif *cif)
 {
   /* All this is for the SYSV and LINUX64 ABI.  */
   int i;
@@ -467,10 +552,10 @@
         Redo the calculation for SYSV.  */
 
       /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
-      bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
+      bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int);
 
       /* Space for the GPR registers.  */
-      bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+      bytes += NUM_GPR_ARG_REGISTERS * sizeof (int);
     }
   else
     {
@@ -478,15 +563,10 @@
 
       /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
         regs.  */
-      bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof(long);
+      bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
 
       /* Space for the mandatory parm save area and general registers.  */
-      bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof(long);
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-      if (type == FFI_TYPE_LONGDOUBLE)
-       type = FFI_TYPE_DOUBLE;
-#endif
+      bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
     }
 
   /* Return value handling.  The rules for SYSV are as follows:
@@ -495,14 +575,24 @@
      - 64-bit integer values and structures between 5 and 8 bytes are returned
      in gpr3 and gpr4;
      - Single/double FP values are returned in fpr1;
-     - Larger structures and long double (if not equivalent to double) values
-     are allocated space and a pointer is passed as the first argument.
+     - Larger structures are allocated space and a pointer is passed as
+     the first argument.
+     - long doubles (if not equivalent to double) are returned in
+     fpr1,fpr2 for Linux and as for large structs for SysV.
      For LINUX64:
      - integer values in gpr3;
      - Structures/Unions by reference;
      - Single/double FP values in fpr1, long double in fpr1,fpr2.  */
   switch (type)
     {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+    case FFI_TYPE_LONGDOUBLE:
+      if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64)
+       goto byref;
+
+      flags |= FLAG_RETURNS_128BITS;
+      /* Fall through.  */
+#endif
     case FFI_TYPE_DOUBLE:
       flags |= FLAG_RETURNS_64BITS;
       /* Fall through.  */
@@ -523,33 +613,29 @@
             in memory.  */
 
          /* Treat structs with size <= 8 bytes.  */
-         if (size <= 8) {
+         if (size <= 8)
+           {
            flags |= FLAG_RETURNS_SMST;
            /* These structs are returned in r3. We pack the type and the
               precalculated shift value (needed in the sysv.S) into flags.
               The same applies for the structs returned in r3/r4.  */
-           if (size <= 4) {
-             flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1 )
-               | (8 * (4 - size) << 4);
+             if (size <= 4)
+               {
+                 flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1);
+                 flags |= 8 * (4 - size) << 4;
              break;
            }
            /* These structs are returned in r3 and r4. See above.   */
-           if  (size <= 8) {
-             flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2 )
-               | (8 * (8 - size) << 4);
+             if  (size <= 8)
+               {
+                 flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2);
+                 flags |= 8 * (8 - size) << 4;
            break;
            }
          }
        }
-      /* else fall through.  */
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-    case FFI_TYPE_LONGDOUBLE:
-      if (type == FFI_TYPE_LONGDOUBLE && cif->abi == FFI_LINUX64)
-       {
-         flags |= FLAG_RETURNS_128BITS;
-         flags |= FLAG_RETURNS_FP;
-         break;
-       }
+    byref:
 #endif
       intarg_count++;
       flags |= FLAG_RETVAL_REFERENCE;
@@ -578,6 +664,13 @@
            /* floating singles are not 8-aligned on stack */
            break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+         case FFI_TYPE_LONGDOUBLE:
+           if (cif->abi != FFI_LINUX)
+             goto do_struct;
+           fparg_count++;
+           /* Fall thru */
+#endif
          case FFI_TYPE_DOUBLE:
            fparg_count++;
            /* If this FP arg is going on the stack, it must be
@@ -600,14 +693,14 @@
               (r7,r8), (r9,r10).
            */
            if (intarg_count == NUM_GPR_ARG_REGISTERS-1
-               || intarg_count%2 != 0)
+               || intarg_count % 2 != 0)
              intarg_count++;
            intarg_count += 2;
            break;
 
          case FFI_TYPE_STRUCT:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-         case FFI_TYPE_LONGDOUBLE:
+         do_struct:
 #endif
            /* We must allocate space for a copy of these to enforce
               pass-by-value.  Pad the space up to a multiple of 16
@@ -663,23 +756,23 @@
     {
       /* Space for the FPR registers, if needed.  */
       if (fparg_count != 0)
-       bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
+       bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
 
       /* Stack space.  */
       if (intarg_count > NUM_GPR_ARG_REGISTERS)
-       bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
+       bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
       if (fparg_count > NUM_FPR_ARG_REGISTERS)
-       bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
+       bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
     }
   else
     {
       /* Space for the FPR registers, if needed.  */
       if (fparg_count != 0)
-       bytes += NUM_FPR_ARG_REGISTERS64 * sizeof(double);
+       bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
 
       /* Stack space.  */
       if (intarg_count > NUM_GPR_ARG_REGISTERS64)
-       bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof(long);
+       bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
     }
 
   /* The stack space allocated needs to be a multiple of 16 bytes.  */
@@ -694,23 +787,14 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(/address@hidden@*/ extended_cif *,
-                         unsigned, unsigned,
-                         /address@hidden@*/ unsigned *,
+extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *,
                          void (*fn)());
-extern void FFI_HIDDEN ffi_call_LINUX64(/address@hidden@*/ extended_cif *,
-                                       unsigned long, unsigned long,
-                                       /address@hidden@*/ unsigned long *,
+extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long,
+                                       unsigned long, unsigned long *,
                                        void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif,
-             void (*fn)(),
-             /address@hidden@*/ void *rvalue,
-             /address@hidden@*/ void **avalue)
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -720,12 +804,9 @@
   /* 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))
+  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -736,49 +817,43 @@
 #ifndef POWERPC64
     case FFI_SYSV:
     case FFI_GCC_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(&ecif, -cif->bytes,
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+    case FFI_LINUX:
+      ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
       break;
 #else
     case FFI_LINUX64:
-      /address@hidden@*/
-      ffi_call_LINUX64(&ecif, -(long) cif->bytes,
-                      cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, 
fn);
       break;
 #endif
     default:
-      FFI_ASSERT(0);
+      FFI_ASSERT (0);
       break;
     }
 }
 
 
 #ifndef POWERPC64
-static void flush_icache(char *, int);
-
 #define MIN_CACHE_LINE_SIZE 8
 
-static void flush_icache(char * addr1, int size)
+static void
+flush_icache (char *wraddr, char *xaddr, int size)
 {
   int i;
-  char * addr;
-  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
-    addr = addr1 + i;
-    __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
-  }
-  addr = addr1 + size - 1;
-  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : 
"memory");
+  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
+    __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
+                     : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
+  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
+                   : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
+                   : "memory");
 }
 #endif
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
-                 ffi_cif* cif,
-                 void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+ffi_prep_closure_loc (ffi_closure *closure,
+                     ffi_cif *cif,
+                     void (*fun) (ffi_cif *, void *, void **, void *),
+                     void *user_data,
+                     void *codeloc)
 {
 #ifdef POWERPC64
   void **tramp = (void **) &closure->tramp[0];
@@ -786,7 +861,7 @@
   FFI_ASSERT (cif->abi == FFI_LINUX64);
   /* Copy function address and TOC from ffi_closure_LINUX64.  */
   memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
-  tramp[2] = (void *) closure;
+  tramp[2] = codeloc;
 #else
   unsigned int *tramp;
 
@@ -801,11 +876,11 @@
   tramp[7] = 0x816b0004;  /*   lwz     r11,4(r11) */
   tramp[8] = 0x7c0903a6;  /*   mtctr   r0 */
   tramp[9] = 0x4e800420;  /*   bctr */
-  *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
-  *(void **) &tramp[3] = (void *)closure;          /* context */
+  *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */
+  *(void **) &tramp[3] = codeloc;                   /* context */
 
   /* Flush the icache.  */
-  flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+  flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
 #endif
 
   closure->cif = cif;
@@ -821,8 +896,8 @@
   double d;
 } ffi_dblfl;
 
-int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
-                            ffi_dblfl*, unsigned long*);
+int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *,
+                            ffi_dblfl *, unsigned long *);
 
 /* Basically the trampoline invokes ffi_closure_SYSV, and on
  * entry, r11 holds the address of the closure.
@@ -833,9 +908,9 @@
  */
 
 int
-ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
-                        unsigned long * pgr, ffi_dblfl * pfr,
-                        unsigned long * pst)
+ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
+                        unsigned long *pgr, ffi_dblfl *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_SYSV */
@@ -852,7 +927,7 @@
   unsigned         size;
 
   cif = closure->cif;
-  avalue = alloca(cif->nargs * sizeof(void *));
+  avalue = alloca (cif->nargs * sizeof (void *));
   size = cif->rtype->size;
 
   nf = 0;
@@ -863,14 +938,18 @@
      For FFI_SYSV the result is passed in r3/r4 if the struct size is less
      or equal 8 bytes.  */
 
-  if (cif->rtype->type == FFI_TYPE_STRUCT)
+  if ((cif->rtype->type == FFI_TYPE_STRUCT
+       && !((cif->abi == FFI_SYSV) && (size <= 8)))
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+         && cif->abi != FFI_LINUX)
+#endif
+      )
     {
-      if (!((cif->abi == FFI_SYSV) && (size <= 8))) {
        rvalue = (void *) *pgr;
        ng++;
        pgr++;
       }
-    }
 
   i = 0;
   avn = cif->nargs;
@@ -884,12 +963,15 @@
        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);
+         if (ng < 8)
+           {
+             avalue[i] = (char *) pgr + 3;
            ng++;
            pgr++;
-         } else {
-           avalue[i] = (((char *)pst)+3);
+           }
+         else
+           {
+             avalue[i] = (char *) pst + 3;
            pst++;
          }
          break;
@@ -897,12 +979,15 @@
        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);
+         if (ng < 8)
+           {
+             avalue[i] = (char *) pgr + 2;
            ng++;
            pgr++;
-         } else {
-           avalue[i] = (((char *)pst)+2);
+           }
+         else
+           {
+             avalue[i] = (char *) pst + 2;
            pst++;
          }
          break;
@@ -911,24 +996,33 @@
        case FFI_TYPE_UINT32:
        case FFI_TYPE_POINTER:
          /* there are 8 gpr registers used to pass values */
-         if (ng < 8) {
+         if (ng < 8)
+           {
            avalue[i] = pgr;
            ng++;
            pgr++;
-         } else {
+           }
+         else
+           {
            avalue[i] = pst;
            pst++;
          }
          break;
 
        case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       do_struct:
+#endif
          /* Structs are passed by reference. The address will appear in a
             gpr if it is one of the first 8 arguments.  */
-         if (ng < 8) {
+         if (ng < 8)
+           {
            avalue[i] = (void *) *pgr;
            ng++;
            pgr++;
-         } else {
+           }
+         else
+           {
            avalue[i] = (void *) *pst;
            pst++;
          }
@@ -945,19 +1039,24 @@
           * or pst to find the correct address for this type
           * of parameter.
           */
-         if (ng < 7) {
-           if (ng & 0x01) {
+         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++;
+             ng += 2;
+             pgr += 2;
+           }
+         else
+           {
+             if (((long) pst) & 4)
+               pst++;
            avalue[i] = pst;
-           pst+=2;
+             pst += 2;
          }
          break;
 
@@ -969,21 +1068,23 @@
 
          /* there are 8 64bit floating point registers */
 
-         if (nf < 8) {
+         if (nf < 8)
+           {
            temp = pfr->d;
-           pfr->f = (float)temp;
+             pfr->f = (float) temp;
            avalue[i] = pfr;
            nf++;
            pfr++;
-         } else {
+           }
+         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...
             */
            avalue[i] = pst;
-           nf++;
-           pst+=1;
+             pst += 1;
          }
          break;
 
@@ -991,20 +1092,45 @@
          /* On the outgoing stack all values are aligned to 8 */
          /* there are 8 64bit floating point registers */
 
-         if (nf < 8) {
+         if (nf < 8)
+           {
            avalue[i] = pfr;
            nf++;
            pfr++;
-         } else {
-           if (((long)pst) & 4) pst++;
+           }
+         else
+           {
+             if (((long) pst) & 4)
+               pst++;
            avalue[i] = pst;
-           nf++;
-           pst+=2;
+             pst += 2;
+           }
+         break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       case FFI_TYPE_LONGDOUBLE:
+         if (cif->abi != FFI_LINUX)
+           goto do_struct;
+
+         if (nf < 7)
+           {
+             avalue[i] = pfr;
+             pfr += 2;
+             nf += 2;
+           }
+         else
+           {
+             if (((long) pst) & 4)
+               pst++;
+             avalue[i] = pst;
+             pst += 4;
+             nf = 8;
          }
          break;
+#endif
 
        default:
-         FFI_ASSERT(0);
+         FFI_ASSERT (0);
        }
 
       i++;
@@ -1019,12 +1145,16 @@
   if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
       && size <= 8)
     return FFI_SYSV_TYPE_SMALL_STRUCT + size;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+  else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+          && cif->abi != FFI_LINUX)
+    return FFI_TYPE_STRUCT;
+#endif
   return cif->rtype->type;
-
 }
 
-int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure*, void*, unsigned long*,
-                                          ffi_dblfl*);
+int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
+                                          unsigned long *, ffi_dblfl *);
 
 int FFI_HIDDEN
 ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
@@ -1153,7 +1283,7 @@
 #endif
 
        default:
-         FFI_ASSERT(0);
+         FFI_ASSERT (0);
        }
 
       i++;

Index: libffi/src/powerpc/ffi_darwin.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/ffi_darwin.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libffi/src/powerpc/ffi_darwin.c     30 Jul 2005 19:00:15 -0000      1.6
+++ libffi/src/powerpc/ffi_darwin.c     30 Nov 2007 20:59:57 -0000      1.7
@@ -1,10 +1,11 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1998 Geoffrey Keating
+   ffi_darwin.c
 
-   PowerPC Foreign Function Interface
+   Copyright (C) 1998 Geoffrey Keating
+   Copyright (C) 2001 John Hornkvist
+   Copyright (C) 2002, 2006, 2007 Free Software Foundation, Inc.
 
-   Darwin ABI support (c) 2001 John Hornkvist
-   AIX ABI support (c) 2002 Free Software Foundation, Inc.
+   FFI support for Darwin and AIX.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -79,9 +80,7 @@
 
    */
 
-/address@hidden@*/
 void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
-/address@hidden@*/
 {
   const unsigned bytes = ecif->cif->bytes;
   const unsigned flags = ecif->cif->flags;
@@ -227,6 +226,48 @@
   //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
 }
 
+/* Adjust the size of S to be correct for Darwin.
+   On Darwin, the first field of a structure has natural alignment.  */
+
+static void
+darwin_adjust_aggregate_sizes (ffi_type *s)
+{
+  int i;
+
+  if (s->type != FFI_TYPE_STRUCT)
+    return;
+
+  s->size = 0;
+  for (i = 0; s->elements[i] != NULL; i++)
+    {
+      ffi_type *p;
+      int align;
+      
+      p = s->elements[i];
+      darwin_adjust_aggregate_sizes (p);
+      if (i == 0
+         && (p->type == FFI_TYPE_UINT64
+             || p->type == FFI_TYPE_SINT64
+             || p->type == FFI_TYPE_DOUBLE
+             || p->alignment == 8))
+       align = 8;
+      else if (p->alignment == 16 || p->alignment < 4)
+       align = p->alignment;
+      else
+       align = 4;
+      s->size = ALIGN(s->size, align) + p->size;
+    }
+  
+  s->size = ALIGN(s->size, s->alignment);
+  
+  if (s->elements[0]->type == FFI_TYPE_UINT64
+      || s->elements[0]->type == FFI_TYPE_SINT64
+      || s->elements[0]->type == FFI_TYPE_DOUBLE
+      || s->elements[0]->alignment == 8)
+    s->alignment = s->alignment > 8 ? s->alignment : 8;
+  /* Do not add additional tail padding.  */
+}
+
 /* Perform machine dependent cif processing.  */
 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 {
@@ -239,8 +280,16 @@
   unsigned size_al = 0;
 
   /* All the machine-independent calculation of cif->bytes will be wrong.
+     All the calculation of structure sizes will also be wrong.
      Redo the calculation for DARWIN.  */
 
+  if (cif->abi == FFI_DARWIN)
+    {
+      darwin_adjust_aggregate_sizes (cif->rtype);
+      for (i = 0; i < cif->nargs; i++)
+       darwin_adjust_aggregate_sizes (cif->arg_types[i]);
+    }
+
   /* Space for the frame pointer, callee's LR, CR, etc, and for
      the asm's temp regs.  */
 
@@ -375,25 +424,12 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_AIX(/address@hidden@*/ extended_cif *,
-                        unsigned, unsigned,
-                        /address@hidden@*/ unsigned *,
-                        void (*fn)(),
-                        void (*fn2)());
-extern void ffi_call_DARWIN(/address@hidden@*/ extended_cif *,
-                           unsigned, unsigned,
-                           /address@hidden@*/ unsigned *,
-                           void (*fn)(),
-                           void (*fn2)());
-/address@hidden@*/
-/address@hidden@*/
-
-void ffi_call(/address@hidden@*/ ffi_cif *cif,
-             void (*fn)(),
-             /address@hidden@*/ void *rvalue,
-             /address@hidden@*/ void **avalue)
+extern void ffi_call_AIX(extended_cif *, unsigned, unsigned, unsigned *,
+                        void (*fn)(), void (*fn2)());
+extern void ffi_call_DARWIN(extended_cif *, unsigned, unsigned, unsigned *,
+                           void (*fn)(), void (*fn2)());
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -406,9 +442,7 @@
   if ((rvalue == NULL) &&
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -416,16 +450,12 @@
   switch (cif->abi)
     {
     case FFI_AIX:
-      /address@hidden@*/
-      ffi_call_AIX(&ecif, -cif->bytes,
-                  cif->flags, ecif.rvalue, fn, ffi_prep_args);
-      /address@hidden@*/
+      ffi_call_AIX(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
+                  ffi_prep_args);
       break;
     case FFI_DARWIN:
-      /address@hidden@*/
-      ffi_call_DARWIN(&ecif, -cif->bytes,
-                     cif->flags, ecif.rvalue, fn, ffi_prep_args);
-      /address@hidden@*/
+      ffi_call_DARWIN(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
+                     ffi_prep_args);
       break;
     default:
       FFI_ASSERT(0);
@@ -498,10 +528,11 @@
 
 */
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp;
   struct ffi_aix_trampoline_struct *tramp_aix;
@@ -523,14 +554,14 @@
       tramp[8] = 0x816b0004;  /*   lwz     r11,4(r11) static chain  */
       tramp[9] = 0x4e800420;  /*   bctr  */
       tramp[2] = (unsigned long) ffi_closure_ASM; /* function  */
-      tramp[3] = (unsigned long) closure; /* context  */
+      tramp[3] = (unsigned long) codeloc; /* 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);
+      flush_range(codeloc, FFI_TRAMPOLINE_SIZE);
 
       break;
 
@@ -543,7 +574,7 @@
 
       tramp_aix->code_pointer = fd->code_pointer;
       tramp_aix->toc = fd->toc;
-      tramp_aix->static_chain = closure;
+      tramp_aix->static_chain = codeloc;
       closure->cif = cif;
       closure->fun = fun;
       closure->user_data = user_data;

Index: libffi/src/powerpc/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/powerpc/ffitarget.h      30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/powerpc/ffitarget.h      30 Nov 2007 20:59:57 -0000      1.2
@@ -43,11 +43,16 @@
   FFI_SYSV,
   FFI_GCC_SYSV,
   FFI_LINUX64,
+  FFI_LINUX,
 # ifdef POWERPC64
   FFI_DEFAULT_ABI = FFI_LINUX64,
 # else
+#  if __LDBL_MANT_DIG__ == 106
+  FFI_DEFAULT_ABI = FFI_LINUX,
+#  else
   FFI_DEFAULT_ABI = FFI_GCC_SYSV,
 # endif
+# endif
 #endif
 
 #ifdef POWERPC_AIX
@@ -69,7 +74,7 @@
   FFI_DEFAULT_ABI = FFI_SYSV,
 #endif
 
-  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+  FFI_LAST_ABI
 } ffi_abi;
 #endif
 

Index: libffi/src/powerpc/linux64.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/linux64.S,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/powerpc/linux64.S        19 Dec 2005 07:07:56 -0000      1.2
+++ libffi/src/powerpc/linux64.S        30 Nov 2007 20:59:57 -0000      1.3
@@ -47,8 +47,8 @@
        std     %r0, 16(%r1)
 
        mr      %r28, %r1       /* our AP.  */
-       stdux   %r1, %r1, %r4
 .LCFI0:
+       stdux   %r1, %r1, %r4
        mr      %r31, %r5       /* flags, */
        mr      %r30, %r6       /* rvalue, */
        mr      %r29, %r7       /* function address.  */
@@ -100,6 +100,10 @@
        /* Make the call.  */
        bctrl
 
+       /* This must follow the call immediately, the unwinder
+          uses this to find out if r2 has been saved or not.  */
+       ld      %r2, 40(%r1)
+
        /* Now, deal with the return value.  */
        mtcrf   0x01, %r31
        bt-     30, .Ldone_return_value
@@ -109,7 +113,6 @@
 
 .Ldone_return_value:
        /* Restore the registers we used and return.  */
-       ld      %r2, 40(%r1)
        mr      %r1, %r28
        ld      %r0, 16(%r28)
        ld      %r28, -32(%r1)
@@ -120,12 +123,10 @@
        blr
 
 .Lfp_return_value:
-       bt      27, .Lfd_return_value
        bf      28, .Lfloat_return_value
        stfd    %f1, 0(%r30)
-       b       .Ldone_return_value
-.Lfd_return_value:
-       stfd    %f1, 0(%r30)
+       mtcrf   0x02, %r31 /* cr6  */
+       bf      27, .Ldone_return_value
        stfd    %f2, 8(%r30)
        b       .Ldone_return_value
 .Lfloat_return_value:

Index: libffi/src/powerpc/ppc_closure.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/ppc_closure.S,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/src/powerpc/ppc_closure.S    17 Aug 2005 19:27:01 -0000      1.4
+++ libffi/src/powerpc/ppc_closure.S    30 Nov 2007 20:59:57 -0000      1.5
@@ -58,30 +58,18 @@
 
        # make the call
        bl address@hidden
-
+.Lret:
        # now r3 contains the return type
        # so use it to look up in a table
        # so we know how to deal with each type
 
-       # Extract the size of the return type for small structures.
-       # Then calculate (4 - size) and multiply the result by 8.
-       # This gives the value needed for the shift operation below.
-       # This part is only needed for FFI_SYSV and small structures.
-       addi    %r5,%r3,-(FFI_SYSV_TYPE_SMALL_STRUCT)
-       cmpwi   cr0,%r5,4
-       ble     cr0,.Lnext
-       addi    %r5,%r5,-4
-.Lnext:
-       addi    %r5,%r5,-4
-       neg     %r5,%r5
-       slwi    %r5,%r5,3
-
        # look up the proper starting point in table
        # by using return type as offset
-       addi %r6,%r1,112   # get pointer to results area
-       bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
-       mflr %r4           # move to r4
+
+       mflr %r4                # move address of .Lret to r4
        slwi %r3,%r3,4     # now multiply return type by 16
+       addi %r4, %r4, .Lret_type0 - .Lret
+       lwz %r0,148(%r1)
        add %r3,%r3,%r4    # add contents of table to table address
        mtctr %r3
        bctr               # jump to it
@@ -91,190 +79,157 @@
 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
 # first.
        .align 4
-
-       nop
-       nop
-       nop
-.Lget_ret_type0_addr:
-       blrl
-
 # case FFI_TYPE_VOID
 .Lret_type0:
-       b .Lfinish
-       nop
-       nop
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
        nop
 
 # case FFI_TYPE_INT
-.Lret_type1:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+.Lfinish:
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_FLOAT
-.Lret_type2:
-       lfs %f1,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lfs %f1,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_DOUBLE
-.Lret_type3:
-       lfd %f1,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lfd %f1,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_LONGDOUBLE
-.Lret_type4:
-       lfd %f1,0(%r6)
+       lfd %f1,112+0(%r1)
+       lfd %f2,112+8(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
-       nop
 
 # case FFI_TYPE_UINT8
-.Lret_type5:
-       lbz %r3,3(%r6)
-       b .Lfinish
-       nop
-       nop
+       lbz %r3,112+3(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT8
-.Lret_type6:
-       lbz %r3,3(%r6)
+       lbz %r3,112+3(%r1)
        extsb %r3,%r3
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_UINT16
-.Lret_type7:
-       lhz %r3,2(%r6)
-       b .Lfinish
-       nop
-       nop
+       lhz %r3,112+2(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT16
-.Lret_type8:
-       lha %r3,2(%r6)
-       b .Lfinish
-       nop
-       nop
+       lha %r3,112+2(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_UINT32
-.Lret_type9:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT32
-.Lret_type10:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_UINT64
-.Lret_type11:
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_SINT64
-.Lret_type12:
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_STRUCT
-.Lret_type13:
-       b .Lfinish
-       nop
-       nop
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
        nop
 
 # case FFI_TYPE_POINTER
-.Lret_type14:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # The return types below are only used when the ABI type is FFI_SYSV.
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
-.Lret_type15:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lbz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
-.Lret_type16:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lhz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
-.Lret_type17:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       srwi %r3,%r3,8
+       mtlr %r0
+       b .Lfinish
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
-.Lret_type18:
-# this one handles the structs from above too.
-       lwz %r3,0(%r6)
-       srw %r3,%r3,%r5
-       b .Lfinish
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
-.Lret_type19:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       li %r5,24
+       b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
-.Lret_type20:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       li %r5,16
+       b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
-.Lret_type21:
-# fall through.
-       nop
-       nop
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       li %r5,8
+       b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
-.Lret_type22:
-# this one handles the above unhandled structs.
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
-       bl __lshrdi3    # libgcc function to shift r3/r4, shift value in r5.
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
 
-# case done
-.Lfinish:
-
-       lwz %r0,148(%r1)
+.Lstruct567:
+       subfic %r6,%r5,32
+       srw %r4,%r4,%r5
+       slw %r6,%r3,%r6
+       srw %r3,%r3,%r5
+       or %r4,%r6,%r4
        mtlr %r0
        addi %r1,%r1,144
        blr
+
 END(ffi_closure_SYSV)
 
        .section        ".eh_frame",EH_FRAME_FLAGS,@progbits

Index: libffi/src/powerpc/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/powerpc/sysv.S,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libffi/src/powerpc/sysv.S   17 Aug 2005 19:27:01 -0000      1.5
+++ libffi/src/powerpc/sysv.S   30 Nov 2007 20:59:57 -0000      1.6
@@ -121,6 +121,9 @@
 L(fp_return_value):
        bf      28,L(float_return_value)
        stfd    %f1,0(%r30)
+       mtcrf   0x02,%r31 /* cr6  */
+       bf      27,L(done_return_value)
+       stfd    %f2,8(%r30)
        b       L(done_return_value)
 L(float_return_value):
        stfs    %f1,0(%r30)
@@ -140,8 +143,14 @@
        b       L(done_return_value)
 L(smst_two_register):
        rlwinm  %r5,%r31,5+23,32-5,31 /* Extract the value to shift.  */
-       bl      __ashldi3  /* libgcc function to shift r3/r4,
-                             shift value in r5.  */
+       cmpwi   %r5,0
+       subfic  %r9,%r5,32
+       slw     %r29,%r3,%r5
+       srw     %r9,%r4,%r9
+       beq-    L(smst_8byte)
+       or      %r3,%r9,%r29
+       slw     %r4,%r4,%r5
+L(smst_8byte):
        stw     %r3,0(%r30)
        stw     %r4,4(%r30)
        b       L(done_return_value)

Index: libffi/src/s390/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/s390/ffi.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libffi/src/s390/ffi.c       30 Jul 2005 19:00:15 -0000      1.4
+++ libffi/src/s390/ffi.c       30 Nov 2007 20:59:57 -0000      1.5
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 2000 Software AG
+   ffi.c - Copyright (c) 2000, 2007 Software AG
  
    S390 Foreign Function Interface
  
@@ -207,6 +207,12 @@
       void *arg = *p_argv;
       int type = (*ptr)->type;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      /* 16-byte long double is passed like a struct.  */
+      if (type == FFI_TYPE_LONGDOUBLE)
+       type = FFI_TYPE_STRUCT;
+#endif
+
       /* Check how a structure type is passed.  */
       if (type == FFI_TYPE_STRUCT)
        {
@@ -364,6 +370,12 @@
        cif->flags = FFI390_RET_DOUBLE;
        break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      case FFI_TYPE_LONGDOUBLE:
+       cif->flags = FFI390_RET_STRUCT;
+       n_gpr++;
+       break;
+#endif
       /* Integer values are returned in gpr 2 (and gpr 3
         for 64-bit values on 31-bit machines).  */
       case FFI_TYPE_UINT64:
@@ -400,6 +412,12 @@
     {
       int type = (*ptr)->type;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      /* 16-byte long double is passed like a struct.  */
+      if (type == FFI_TYPE_LONGDOUBLE)
+       type = FFI_TYPE_STRUCT;
+#endif
+
       /* Check how a structure type is passed.  */
       if (type == FFI_TYPE_STRUCT)
        {
@@ -562,6 +580,12 @@
       int deref_struct_pointer = 0;
       int type = (*ptr)->type;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      /* 16-byte long double is passed like a struct.  */
+      if (type == FFI_TYPE_LONGDOUBLE)
+       type = FFI_TYPE_STRUCT;
+#endif
+
       /* Check how a structure type is passed.  */
       if (type == FFI_TYPE_STRUCT)
        {
@@ -662,6 +686,9 @@
       /* Void is easy, and so is struct.  */
       case FFI_TYPE_VOID:
       case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      case FFI_TYPE_LONGDOUBLE:
+#endif
        break;
 
       /* Floating point values are returned in fpr 0.  */
@@ -709,17 +736,18 @@
 
 /*====================================================================*/
 /*                                                                    */
-/* Name     - ffi_prep_closure.                                       */
+/* Name     - ffi_prep_closure_loc.                                   */
 /*                                                                    */
 /* Function - Prepare a FFI closure.                                  */
 /*                                                                    */
 /*====================================================================*/
  
 ffi_status
-ffi_prep_closure (ffi_closure *closure,
+ffi_prep_closure_loc (ffi_closure *closure,
                   ffi_cif *cif,
                   void (*fun) (ffi_cif *, void *, void **, void *),
-                  void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   FFI_ASSERT (cif->abi == FFI_SYSV);
 
@@ -728,7 +756,7 @@
   *(short *)&closure->tramp [2] = 0x9801;   /* lm %r0,%r1,6(%r1) */
   *(short *)&closure->tramp [4] = 0x1006;
   *(short *)&closure->tramp [6] = 0x07f1;   /* br %r1 */
-  *(long  *)&closure->tramp [8] = (long)closure;
+  *(long  *)&closure->tramp [8] = (long)codeloc;
   *(long  *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
 #else
   *(short *)&closure->tramp [0] = 0x0d10;   /* basr %r1,0 */
@@ -736,7 +764,7 @@
   *(short *)&closure->tramp [4] = 0x100e;
   *(short *)&closure->tramp [6] = 0x0004;
   *(short *)&closure->tramp [8] = 0x07f1;   /* br %r1 */
-  *(long  *)&closure->tramp[16] = (long)closure;
+  *(long  *)&closure->tramp[16] = (long)codeloc;
   *(long  *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
 #endif 
  

Index: libffi/src/sh/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/sh/ffi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/sh/ffi.c 30 Jul 2005 19:00:15 -0000      1.2
+++ libffi/src/sh/ffi.c 30 Nov 2007 20:59:57 -0000      1.3
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 2002, 2003, 2004, 2005 Kaz Kojima
+   ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Kaz Kojima
    
    SuperH Foreign Function Interface 
 
@@ -106,9 +106,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-/address@hidden@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/address@hidden@*/
 {
   register unsigned int i;
   register int tmp;
@@ -406,20 +404,10 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /address@hidden@*/ extended_cif *, 
-                         unsigned, unsigned, 
-                         /address@hidden@*/ unsigned *, 
-                         void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
-
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue)
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)());
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
   UINT64 trvalue;
@@ -436,9 +424,7 @@
   else if ((rvalue == NULL) && 
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -446,10 +432,8 @@
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                   fn);
       break;
     default:
       FFI_ASSERT(0);
@@ -468,10 +452,11 @@
 #endif
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp;
   unsigned short insn;
@@ -491,7 +476,7 @@
   tramp[0] = 0xd102d301;
   tramp[1] = 0x412b0000 | insn;
 #endif
-  *(void **) &tramp[2] = (void *)closure;          /* ctx */
+  *(void **) &tramp[2] = (void *)codeloc;          /* ctx */
   *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
 
   closure->cif = cif;
@@ -500,7 +485,7 @@
 
 #if defined(__SH4__)
   /* Flush the icache.  */
-  __ic_invalidate(&closure->tramp[0]);
+  __ic_invalidate(codeloc);
 #endif
 
   return FFI_OK;
@@ -535,7 +520,6 @@
   int freg = 0;
 #endif
   ffi_cif *cif; 
-  double temp; 
 
   cif = closure->cif;
   avalue = alloca(cif->nargs * sizeof(void *));
@@ -544,7 +528,7 @@
      returns the data directly to the caller.  */
   if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
     {
-      rvalue = *pgr++;
+      rvalue = (void *) *pgr++;
       ireg = 1;
     }
   else
@@ -611,6 +595,8 @@
        {
          if (freg + 1 >= NFREGARG)
            continue;
+         if (freg & 1)
+           pfr++;
          freg = (freg + 1) & ~1;
          freg += 2;
          avalue[i] = pfr;

Index: libffi/src/sh/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/sh/sysv.S,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libffi/src/sh/sysv.S        30 Jul 2005 19:00:15 -0000      1.2
+++ libffi/src/sh/sysv.S        30 Nov 2007 20:59:57 -0000      1.3
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   sysv.S - Copyright (c) 2002, 2003, 2004 Kaz Kojima
+   sysv.S - Copyright (c) 2002, 2003, 2004, 2006 Kaz Kojima
    
    SuperH Foreign Function Interface 
 
@@ -829,13 +829,13 @@
        .byte   0x6     /* uleb128 0x6 */
        .byte   0x8e    /* DW_CFA_offset, column 0xe */
        .byte   0x5     /* uleb128 0x5 */
-       .byte   0x8b    /* DW_CFA_offset, column 0xb */
+       .byte   0x84    /* DW_CFA_offset, column 0x4 */
        .byte   0x4     /* uleb128 0x4 */
-       .byte   0x8a    /* DW_CFA_offset, column 0xa */
+       .byte   0x85    /* DW_CFA_offset, column 0x5 */
        .byte   0x3     /* uleb128 0x3 */
-       .byte   0x89    /* DW_CFA_offset, column 0x9 */
+       .byte   0x86    /* DW_CFA_offset, column 0x6 */
        .byte   0x2     /* uleb128 0x2 */
-       .byte   0x88    /* DW_CFA_offset, column 0x8 */
+       .byte   0x87    /* DW_CFA_offset, column 0x7 */
        .byte   0x1     /* uleb128 0x1 */
        .byte   0x4     /* DW_CFA_advance_loc4 */
        .4byte  .LCFIE-.LCFID

Index: libffi/src/sh64/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/sh64/ffi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/sh64/ffi.c       30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/sh64/ffi.c       30 Nov 2007 20:59:57 -0000      1.2
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 2003, 2004 Kaz Kojima
+   ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
    
    SuperH SHmedia Foreign Function Interface 
 
@@ -54,9 +54,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-/address@hidden@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/address@hidden@*/
 {
   register unsigned int i;
   register unsigned int avn;
@@ -160,6 +158,7 @@
   int n, m;
   int greg;
   int freg;
+  int fpair = -1;
 
   greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
   freg = 0;
@@ -175,7 +174,13 @@
          cif->bytes += sizeof (UINT64) - sizeof (float);
          if (freg >= NFREGARG - 1)
            continue;
-         freg++;
+         if (fpair < 0)
+           {
+             fpair = freg;
+             freg += 2;
+           }
+         else
+           fpair = -1;
          cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
          break;
 
@@ -184,7 +189,6 @@
            continue;
          if ((freg + 1) < NFREGARG)
            {
-             freg = (freg + 1) & ~1;
              freg += 2;
              cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
            }
@@ -232,20 +236,11 @@
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /address@hidden@*/ extended_cif *, 
-                         unsigned, unsigned, long long,
-                         /address@hidden@*/ unsigned *, 
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, long long, unsigned *,
                          void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue)
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
   UINT64 trvalue;
@@ -262,9 +257,7 @@
   else if ((rvalue == NULL) && 
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -272,10 +265,8 @@
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
-                   cif->flags, cif->flags2, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
+                   ecif.rvalue, fn);
       break;
     default:
       FFI_ASSERT(0);
@@ -292,10 +283,11 @@
 extern void __ic_invalidate (void *line);
 
 ffi_status
-ffi_prep_closure (ffi_closure *closure,
+ffi_prep_closure_loc (ffi_closure *closure,
                  ffi_cif *cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp;
 
@@ -319,8 +311,8 @@
   tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
   tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
   tramp[4] = 0x6bf10600;
-  tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
-  tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
+  tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
+  tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
   tramp[7] = 0x4401fff0;
 
   closure->cif = cif;
@@ -328,7 +320,8 @@
   closure->user_data = user_data;
 
   /* Flush the icache.  */
-  asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
+  asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
+               "r"(codeloc));
 
   return FFI_OK;
 }
@@ -350,6 +343,7 @@
   int i, avn;
   int greg, freg;
   ffi_cif *cif;
+  int fpair = -1;
 
   cif = closure->cif;
   avalue = alloca (cif->nargs * sizeof (void *));
@@ -358,7 +352,7 @@
      returns the data directly to the caller.  */
   if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
     {
-      rvalue = *pgr;
+      rvalue = (UINT64 *) *pgr;
       greg = 1;
     }
   else
@@ -402,11 +396,24 @@
          if ((*p_arg)->type == FFI_TYPE_FLOAT)
            {
              if (freg < NFREGARG - 1)
+               {
+                 if (fpair >= 0)
+                   {
+                     avalue[i] = (UINT32 *) pfr + fpair;
+                     fpair = -1;
+                   }
+                 else
+                   {
 #ifdef __LITTLE_ENDIAN__
-               avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
+                     fpair = freg;
+                     avalue[i] = (UINT32 *) pfr + (1 ^ freg);
 #else
-               avalue[i] = (UINT32 *) pfr + freg++;
+                     fpair = 1 ^ freg;
+                     avalue[i] = (UINT32 *) pfr + freg;
 #endif
+                     freg += 2;
+                   }
+               }
              else
 #ifdef __LITTLE_ENDIAN__
                avalue[i] = pgr + greg;
@@ -428,7 +435,6 @@
            avalue[i] = pgr + greg;
          else
            {
-             freg = (freg + 1) & ~1;
              avalue[i] = pfr + (freg >> 1);
              freg += 2;
            }

Index: libffi/src/sh64/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/sh64/sysv.S,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/sh64/sysv.S      30 Jul 2005 19:00:15 -0000      1.1
+++ libffi/src/sh64/sysv.S      30 Nov 2007 20:59:57 -0000      1.2
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   sysv.S - Copyright (c) 2003, 2004 Kaz Kojima
+   sysv.S - Copyright (c) 2003, 2004, 2006 Kaz Kojima
    
    SuperH SHmedia Foreign Function Interface 
 
@@ -84,6 +84,7 @@
        addi    r15, 64, r22
        movi    0, r0
        movi    0, r1
+       movi    -1, r23
 
        pt/l    1f, tr1
        bnei/l  r29, FFI_TYPE_STRUCT, tr1
@@ -106,9 +107,6 @@
 
 .L_pass_d:
        addi    r0, 1, r0
-       addi    r1, 1, r1
-       andi    r1, ~1, r1
-
        pt/l    3f, tr0
        movi    12, r20
        bge/l   r1, r20, tr0
@@ -158,13 +156,23 @@
        addi.l  r15, 8, r15
 3:
        pt/l    .L_pass, tr0
-       addi    r1, 1, r1
        blink   tr0, r63
 
 .L_pop_f:
        pt/l    .L_pop_f_tbl, tr1
+       pt/l    5f, tr2
        gettr   tr1, r20
+       bge/l   r23, r63, tr2
+       add     r1, r63, r23 
        shlli   r1, 3, r21
+       addi    r1, 2, r1
+       add     r20, r21, r20
+       ptabs/l r20, tr1
+       blink   tr1, r63
+5:
+       addi    r23, 1, r21
+       movi    -1, r23
+       shlli   r21, 3, r21
        add     r20, r21, r20
        ptabs/l r20, tr1
        blink   tr1, r63

Index: libffi/src/sparc/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/sparc/ffi.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/sparc/ffi.c      30 Jul 2005 19:00:15 -0000      1.3
+++ libffi/src/sparc/ffi.c      30 Nov 2007 20:59:57 -0000      1.4
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
+   ffi.c - Copyright (c) 1996, 2003, 2004, 2007 Red Hat, Inc.
    
    SPARC Foreign Function Interface 
 
@@ -425,10 +425,11 @@
 #endif
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
   unsigned long fn;
@@ -443,7 +444,7 @@
   tramp[3] = 0x01000000;       /* nop                  */
   *((unsigned long *) &tramp[4]) = fn;
 #else
-  unsigned long ctx = (unsigned long) closure;
+  unsigned long ctx = (unsigned long) codeloc;
   FFI_ASSERT (cif->abi == FFI_V8);
   fn = (unsigned long) ffi_closure_v8;
   tramp[0] = 0x03000000 | fn >> 10;    /* sethi %hi(fn), %g1   */

Index: libffi/src/x86/ffi.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/x86/ffi.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libffi/src/x86/ffi.c        17 Aug 2005 19:27:01 -0000      1.6
+++ libffi/src/x86/ffi.c        30 Nov 2007 20:59:57 -0000      1.7
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1996, 1998, 1999, 2001  Red Hat, Inc.
+   ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007  Red Hat, Inc.
            Copyright (c) 2002  Ranjit Mathew
            Copyright (c) 2002  Bo Thorsen
            Copyright (c) 2002  Roger Sayle
@@ -36,9 +36,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-/address@hidden@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/address@hidden@*/
 {
   register unsigned int i;
   register void **p_argv;
@@ -121,9 +119,14 @@
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
-#ifndef X86_WIN32
+#ifdef X86
     case FFI_TYPE_STRUCT:
+    case FFI_TYPE_UINT8:
+    case FFI_TYPE_UINT16:
+    case FFI_TYPE_SINT8:
+    case FFI_TYPE_SINT16:
 #endif
+
     case FFI_TYPE_SINT64:
     case FFI_TYPE_FLOAT:
     case FFI_TYPE_DOUBLE:
@@ -135,7 +138,7 @@
       cif->flags = FFI_TYPE_SINT64;
       break;
 
-#ifdef X86_WIN32
+#ifndef X86
     case FFI_TYPE_STRUCT:
       if (cif->rtype->size == 1)
         {
@@ -165,35 +168,23 @@
       break;
     }
 
+#ifdef X86_DARWIN
+  cif->bytes = (cif->bytes + 15) & ~0xF;
+#endif
+
   return FFI_OK;
 }
 
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /address@hidden@*/ extended_cif *, 
-                         unsigned, unsigned, 
-                         /address@hidden@*/ unsigned *, 
-                         void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)());
 
 #ifdef X86_WIN32
-/address@hidden@*/
-/address@hidden@*/
-extern void ffi_call_STDCALL(void (*)(char *, extended_cif *),
-                         /address@hidden@*/ extended_cif *,
-                         unsigned, unsigned,
-                         /address@hidden@*/ unsigned *,
-                         void (*fn)());
-/address@hidden@*/
-/address@hidden@*/
+extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)());
+
 #endif /* X86_WIN32 */
 
-void ffi_call(/address@hidden@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /address@hidden@*/ void *rvalue, 
-             /address@hidden@*/ void **avalue)
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -206,9 +197,7 @@
   if ((rvalue == NULL) && 
       (cif->flags == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -217,17 +206,13 @@
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                   fn);
       break;
 #ifdef X86_WIN32
     case FFI_STDCALL:
-      /address@hidden@*/
-      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
+                      ecif.rvalue, fn);
       break;
 #endif /* X86_WIN32 */
     default:
@@ -276,11 +261,9 @@
   return cif->flags;
 }
 
-/address@hidden@*/
 static void 
-ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
-                           void **avalue, ffi_cif *cif)
-/address@hidden@*/
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
+                           ffi_cif *cif)
 {
   register unsigned int i;
   register void **p_argv;
@@ -324,7 +307,7 @@
 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
    unsigned int  __fun = (unsigned int)(FUN); \
    unsigned int  __ctx = (unsigned int)(CTX); \
-   unsigned int  __dis = __fun - ((unsigned int) __tramp + 
FFI_TRAMPOLINE_SIZE); \
+   unsigned int  __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
    *(unsigned char*) &__tramp[0] = 0xb8; \
    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
    *(unsigned char *)  &__tramp[5] = 0xe9; \
@@ -335,16 +318,17 @@
 /* the cif must already be prep'ed */
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*,void*,void**,void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   FFI_ASSERT (cif->abi == FFI_SYSV);
 
   FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
                       &ffi_closure_SYSV,  \
-                      (void*)closure);
+                      codeloc);
     
   closure->cif  = cif;
   closure->user_data = user_data;
@@ -358,10 +342,11 @@
 #if !FFI_NO_RAW_API
 
 ffi_status
-ffi_prep_raw_closure (ffi_raw_closure* closure,
+ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
                      ffi_cif* cif,
                      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
-                     void *user_data)
+                         void *user_data,
+                         void *codeloc)
 {
   int i;
 
@@ -380,7 +365,7 @@
   
 
   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
-                      (void*)closure);
+                      codeloc);
     
   closure->cif  = cif;
   closure->user_data = user_data;
@@ -401,26 +386,17 @@
  */
 
 extern void 
-ffi_call_SYSV(void (*)(char *, extended_cif *), 
-             /address@hidden@*/ extended_cif *, 
-             unsigned, unsigned, 
-             /address@hidden@*/ unsigned *, 
-             void (*fn)());
+ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, 
+             unsigned, unsigned *, void (*fn)());
 
 #ifdef X86_WIN32
 extern void
-ffi_call_STDCALL(void (*)(char *, extended_cif *),
-             /address@hidden@*/ extended_cif *,
-             unsigned, unsigned,
-             /address@hidden@*/ unsigned *,
-             void (*fn)());
+ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
+                unsigned, unsigned *, void (*fn)());
 #endif /* X86_WIN32 */
 
 void
-ffi_raw_call(/address@hidden@*/ ffi_cif *cif, 
-            void (*fn)(), 
-            /address@hidden@*/ void *rvalue, 
-            /address@hidden@*/ ffi_raw *fake_avalue)
+ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
 {
   extended_cif ecif;
   void **avalue = (void **)fake_avalue;
@@ -434,9 +410,7 @@
   if ((rvalue == NULL) && 
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /address@hidden@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /address@hidden@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -445,17 +419,13 @@
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /address@hidden@*/
-      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                   ecif.rvalue, fn);
       break;
 #ifdef X86_WIN32
     case FFI_STDCALL:
-      /address@hidden@*/
-      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
-                   cif->flags, ecif.rvalue, fn);
-      /address@hidden@*/
+      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                      ecif.rvalue, fn);
       break;
 #endif /* X86_WIN32 */
     default:

Index: libffi/src/x86/ffi64.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/x86/ffi64.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libffi/src/x86/ffi64.c      30 Jul 2005 19:00:15 -0000      1.3
+++ libffi/src/x86/ffi64.c      30 Nov 2007 20:59:58 -0000      1.4
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 2002  Bo Thorsen <address@hidden>
+   ffi.c - Copyright (c) 2002, 2007  Bo Thorsen <address@hidden>
    
    x86-64 Foreign Function Interface 
 
@@ -433,10 +433,11 @@
 extern void ffi_closure_unix64(void);
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure* closure,
                  ffi_cif* cif,
                  void (*fun)(ffi_cif*, void*, void**, void*),
-                 void *user_data)
+                     void *user_data,
+                     void *codeloc)
 {
   volatile unsigned short *tramp;
 
@@ -445,7 +446,7 @@
   tramp[0] = 0xbb49;           /* mov <code>, %r11     */
   *(void * volatile *) &tramp[1] = ffi_closure_unix64;
   tramp[5] = 0xba49;           /* mov <data>, %r10     */
-  *(void * volatile *) &tramp[6] = closure;
+  *(void * volatile *) &tramp[6] = codeloc;
 
   /* Set the carry bit iff the function uses any sse registers.
      This is clc or stc, together with the first byte of the jmp.  */

Index: libffi/src/x86/ffitarget.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/x86/ffitarget.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libffi/src/x86/ffitarget.h  30 Jul 2005 19:04:07 -0000      1.1
+++ libffi/src/x86/ffitarget.h  30 Nov 2007 20:59:58 -0000      1.2
@@ -69,7 +69,7 @@
 
 #define FFI_CLOSURES 1
 
-#ifdef X86_64
+#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
 #define FFI_TRAMPOLINE_SIZE 24
 #define FFI_NATIVE_RAW_API 0
 #else

Index: libffi/src/x86/sysv.S
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/libffi/src/x86/sysv.S,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libffi/src/x86/sysv.S       17 Aug 2005 19:27:01 -0000      1.5
+++ libffi/src/x86/sysv.S       30 Nov 2007 20:59:58 -0000      1.6
@@ -59,16 +59,15 @@
 
        call  *28(%ebp)
 
-       /* Remove the space we pushed for the args  */
-       movl  16(%ebp),%ecx
-       addl  %ecx,%esp
-
        /* Load %ecx with the return type code  */
        movl  20(%ebp),%ecx     
 
+       /* Protect %esi.  We're going to pop it in the epilogue.  */
+       pushl %esi
+
        /* If the return value pointer is NULL, assume no return value.  */
        cmpl  $0,24(%ebp)
-       jne   retint
+       jne  0f
 
        /* Even if there is no space for the return value, we are 
           obliged to handle floating-point values.  */
@@ -78,51 +77,84 @@
 
         jmp   epilogue
 
-retint:
-       cmpl  $FFI_TYPE_INT,%ecx
-       jne   retfloat
-       /* Load %ecx with the pointer to storage for the return value  */
-       movl  24(%ebp),%ecx     
-       movl  %eax,0(%ecx)
-       jmp   epilogue
+0:
+       call  1f
+
+.Lstore_table:
+       .long   noretval-.Lstore_table  /* FFI_TYPE_VOID */
+       .long   retint-.Lstore_table    /* FFI_TYPE_INT */
+       .long   retfloat-.Lstore_table  /* FFI_TYPE_FLOAT */
+       .long   retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
+       .long   retlongdouble-.Lstore_table     /* FFI_TYPE_LONGDOUBLE */
+       .long   retuint8-.Lstore_table  /* FFI_TYPE_UINT8 */
+       .long   retsint8-.Lstore_table  /* FFI_TYPE_SINT8 */
+       .long   retuint16-.Lstore_table /* FFI_TYPE_UINT16 */
+       .long   retsint16-.Lstore_table /* FFI_TYPE_SINT16 */
+       .long   retint-.Lstore_table    /* FFI_TYPE_UINT32 */
+       .long   retint-.Lstore_table    /* FFI_TYPE_SINT32 */
+       .long   retint64-.Lstore_table  /* FFI_TYPE_UINT64 */
+       .long   retint64-.Lstore_table  /* FFI_TYPE_SINT64 */
+       .long   retstruct-.Lstore_table /* FFI_TYPE_STRUCT */
+       .long   retint-.Lstore_table    /* FFI_TYPE_POINTER */
+
+1:
+       pop  %esi
+       add  (%esi, %ecx, 4), %esi
+       jmp  *%esi
+
+       /* Sign/zero extend as appropriate.  */
+retsint8:
+       movsbl  %al, %eax
+       jmp  retint
+
+retsint16:
+       movswl  %ax, %eax
+       jmp  retint
+
+retuint8:
+       movzbl  %al, %eax
+       jmp  retint
+
+retuint16:
+       movzwl  %ax, %eax
+       jmp  retint
 
 retfloat:
-       cmpl  $FFI_TYPE_FLOAT,%ecx
-       jne   retdouble
        /* Load %ecx with the pointer to storage for the return value  */
        movl  24(%ebp),%ecx     
        fstps (%ecx)
        jmp   epilogue
 
 retdouble:
-       cmpl  $FFI_TYPE_DOUBLE,%ecx
-       jne   retlongdouble
        /* Load %ecx with the pointer to storage for the return value  */
        movl  24(%ebp),%ecx     
        fstpl (%ecx)
        jmp   epilogue
 
 retlongdouble:
-       cmpl  $FFI_TYPE_LONGDOUBLE,%ecx
-       jne   retint64
        /* Load %ecx with the pointer to storage for the return value  */
        movl  24(%ebp),%ecx     
        fstpt (%ecx)
        jmp   epilogue
        
 retint64:      
-       cmpl  $FFI_TYPE_SINT64,%ecx
-        jne   retstruct
        /* Load %ecx with the pointer to storage for the return value  */
        movl  24(%ebp),%ecx     
        movl  %eax,0(%ecx)
        movl  %edx,4(%ecx)
+       jmp   epilogue
+       
+retint:
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       movl  %eax,0(%ecx)
        
 retstruct:
        /* Nothing to do!  */
 
 noretval:
 epilogue:
+        popl %esi
         movl %ebp,%esp
         popl %ebp
         ret
@@ -162,7 +194,15 @@
        movl    -12(%ebp), %ecx
        cmpl    $FFI_TYPE_INT, %eax
        je      .Lcls_retint
-       cmpl    $FFI_TYPE_FLOAT, %eax
+
+       /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
+          FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32.  */
+       cmpl    $FFI_TYPE_UINT64, %eax
+       jge     0f
+       cmpl    $FFI_TYPE_UINT8, %eax
+       jge     .Lcls_retint
+       
+0:     cmpl    $FFI_TYPE_FLOAT, %eax
        je      .Lcls_retfloat
        cmpl    $FFI_TYPE_DOUBLE, %eax
        je      .Lcls_retdouble
@@ -226,6 +266,14 @@
        movl    CIF_FLAGS_OFFSET(%esi), %eax             /* rtype */
        cmpl    $FFI_TYPE_INT, %eax
        je      .Lrcls_retint
+
+       /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
+          FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32.  */
+       cmpl    $FFI_TYPE_UINT64, %eax
+       jge     0f
+       cmpl    $FFI_TYPE_UINT8, %eax
+       jge     .Lrcls_retint
+0:
        cmpl    $FFI_TYPE_FLOAT, %eax
        je      .Lrcls_retfloat
        cmpl    $FFI_TYPE_DOUBLE, %eax

Index: libffi/src/closures.c
===================================================================
RCS file: libffi/src/closures.c
diff -N libffi/src/closures.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libffi/src/closures.c       30 Nov 2007 20:59:55 -0000      1.1
@@ -0,0 +1,574 @@
+/* -----------------------------------------------------------------------
+   closures.c - Copyright (c) 2007  Red Hat, Inc.
+   Copyright (C) 2007 Free Software Foundation, Inc
+
+   Code to allocate and deallocate memory for closures.
+
+   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 CYGNUS SOLUTIONS 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.
+   ----------------------------------------------------------------------- */
+
+#if defined __linux__ && !defined _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#ifndef FFI_MMAP_EXEC_WRIT
+# if __gnu_linux__
+/* This macro indicates it may be forbidden to map anonymous memory
+   with both write and execute permission.  Code compiled when this
+   option is defined will attempt to map such pages once, but if it
+   fails, it falls back to creating a temporary file in a writable and
+   executable filesystem and mapping pages from it into separate
+   locations in the virtual memory space, one location writable and
+   another executable.  */
+#  define FFI_MMAP_EXEC_WRIT 1
+# endif
+#endif
+
+#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
+# ifdef __linux__
+/* When defined to 1 check for SELinux and if SELinux is active,
+   don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
+   might cause audit messages.  */
+#  define FFI_MMAP_EXEC_SELINUX 1
+# endif
+#endif
+
+#if FFI_CLOSURES
+
+# if FFI_MMAP_EXEC_WRIT
+
+#define USE_LOCKS 1
+#define USE_DL_PREFIX 1
+#define USE_BUILTIN_FFS 1
+
+/* We need to use mmap, not sbrk.  */
+#define HAVE_MORECORE 0
+
+/* We could, in theory, support mremap, but it wouldn't buy us anything.  */
+#define HAVE_MREMAP 0
+
+/* We have no use for this, so save some code and data.  */
+#define NO_MALLINFO 1
+
+/* We need all allocations to be in regular segments, otherwise we
+   lose track of the corresponding code address.  */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+
+/* Don't allocate more than a page unless needed.  */
+#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
+
+#if FFI_CLOSURE_TEST
+/* Don't release single pages, to avoid a worst-case scenario of
+   continuously allocating and releasing single pages, but release
+   pairs of pages, which should do just as well given that allocations
+   are likely to be small.  */
+#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <sys/param.h>
+#include <pthread.h>
+
+/* We don't want sys/mman.h to be included after we redefine mmap and
+   dlmunmap.  */
+#include <sys/mman.h>
+#define LACKS_SYS_MMAN_H 1
+
+#if FFI_MMAP_EXEC_SELINUX
+#include <sys/statfs.h>
+#include <stdlib.h>
+
+static int selinux_enabled = -1;
+
+static int
+selinux_enabled_check (void)
+{
+  struct statfs sfs;
+  FILE *f;
+  char *buf = NULL;
+  size_t len = 0;
+
+  if (statfs ("/selinux", &sfs) >= 0
+      && (unsigned int) sfs.f_type == 0xf97cff8cU)
+    return 1;
+  f = fopen ("/proc/mounts", "r");
+  if (f == NULL)
+    return 0;
+  while (getline (&buf, &len, f) >= 0)
+    {
+      char *p = strchr (buf, ' ');
+      if (p == NULL)
+        break;
+      p = strchr (p + 1, ' ');
+      if (p == NULL)
+        break;
+      if (strncmp (p + 1, "selinuxfs ", 10) != 0)
+        {
+          free (buf);
+          fclose (f);
+          return 1;
+        }
+    }
+  free (buf);
+  fclose (f);
+  return 0;
+}
+
+#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
+                             : (selinux_enabled = selinux_enabled_check ()))
+
+#else
+
+#define is_selinux_enabled() 0
+
+#endif
+
+/* Declare all functions defined in dlmalloc.c as static.  */
+static void *dlmalloc(size_t);
+static void dlfree(void*);
+static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
+static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
+static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
+static void *dlvalloc(size_t) MAYBE_UNUSED;
+static int dlmallopt(int, int) MAYBE_UNUSED;
+static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
+static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
+static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
+static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
+static void *dlpvalloc(size_t) MAYBE_UNUSED;
+static int dlmalloc_trim(size_t) MAYBE_UNUSED;
+static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
+static void dlmalloc_stats(void) MAYBE_UNUSED;
+
+/* Use these for mmap and munmap within dlmalloc.c.  */
+static void *dlmmap(void *, size_t, int, int, int, off_t);
+static int dlmunmap(void *, size_t);
+
+#define mmap dlmmap
+#define munmap dlmunmap
+
+#include "dlmalloc.c"
+
+#undef mmap
+#undef munmap
+
+/* A mutex used to synchronize access to *exec* variables in this file.  */
+static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* A file descriptor of a temporary file from which we'll map
+   executable pages.  */
+static int execfd = -1;
+
+/* The amount of space already allocated from the temporary file.  */
+static size_t execsize = 0;
+
+/* Open a temporary file name, and immediately unlink it.  */
+static int
+open_temp_exec_file_name (char *name)
+{
+  int fd = mkstemp (name);
+
+  if (fd != -1)
+    unlink (name);
+
+  return fd;
+}
+
+/* Open a temporary file in the named directory.  */
+static int
+open_temp_exec_file_dir (const char *dir)
+{
+  static const char suffix[] = "/ffiXXXXXX";
+  int lendir = strlen (dir);
+  char *tempname = __builtin_alloca (lendir + sizeof (suffix));
+
+  if (!tempname)
+    return -1;
+
+  memcpy (tempname, dir, lendir);
+  memcpy (tempname + lendir, suffix, sizeof (suffix));
+
+  return open_temp_exec_file_name (tempname);
+}
+
+/* Open a temporary file in the directory in the named environment
+   variable.  */
+static int
+open_temp_exec_file_env (const char *envvar)
+{
+  const char *value = getenv (envvar);
+
+  if (!value)
+    return -1;
+
+  return open_temp_exec_file_dir (value);
+}
+
+/* Open a temporary file in an executable and writable mount point
+   listed in the mounts file.  Subsequent calls with the same mounts
+   keep searching for mount points in the same file.  Providing NULL
+   as the mounts file closes the file.  */
+static int
+open_temp_exec_file_mnt (const char *mounts)
+{
+  static const char *last_mounts;
+  static FILE *last_mntent;
+
+  if (mounts != last_mounts)
+    {
+      if (last_mntent)
+       endmntent (last_mntent);
+
+      last_mounts = mounts;
+
+      if (mounts)
+       last_mntent = setmntent (mounts, "r");
+      else
+       last_mntent = NULL;
+    }
+
+  if (!last_mntent)
+    return -1;
+
+  for (;;)
+    {
+      int fd;
+      struct mntent mnt;
+      char buf[MAXPATHLEN * 3];
+
+      if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
+       return -1;
+
+      if (hasmntopt (&mnt, "ro")
+         || hasmntopt (&mnt, "noexec")
+         || access (mnt.mnt_dir, W_OK))
+       continue;
+
+      fd = open_temp_exec_file_dir (mnt.mnt_dir);
+
+      if (fd != -1)
+       return fd;
+    }
+}
+
+/* Instructions to look for a location to hold a temporary file that
+   can be mapped in for execution.  */
+static struct
+{
+  int (*func)(const char *);
+  const char *arg;
+  int repeat;
+} open_temp_exec_file_opts[] = {
+  { open_temp_exec_file_env, "TMPDIR", 0 },
+  { open_temp_exec_file_dir, "/tmp", 0 },
+  { open_temp_exec_file_dir, "/var/tmp", 0 },
+  { open_temp_exec_file_dir, "/dev/shm", 0 },
+  { open_temp_exec_file_env, "HOME", 0 },
+  { open_temp_exec_file_mnt, "/etc/mtab", 1 },
+  { open_temp_exec_file_mnt, "/proc/mounts", 1 },
+};
+
+/* Current index into open_temp_exec_file_opts.  */
+static int open_temp_exec_file_opts_idx = 0;
+
+/* Reset a current multi-call func, then advances to the next entry.
+   If we're at the last, go back to the first and return nonzero,
+   otherwise return zero.  */
+static int
+open_temp_exec_file_opts_next (void)
+{
+  if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
+    open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
+
+  open_temp_exec_file_opts_idx++;
+  if (open_temp_exec_file_opts_idx
+      == (sizeof (open_temp_exec_file_opts)
+         / sizeof (*open_temp_exec_file_opts)))
+    {
+      open_temp_exec_file_opts_idx = 0;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Return a file descriptor of a temporary zero-sized file in a
+   writable and exexutable filesystem.  */
+static int
+open_temp_exec_file (void)
+{
+  int fd;
+
+  do
+    {
+      fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
+       (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
+
+      if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
+         || fd == -1)
+       {
+         if (open_temp_exec_file_opts_next ())
+           break;
+       }
+    }
+  while (fd == -1);
+
+  return fd;
+}
+
+/* Map in a chunk of memory from the temporary exec file into separate
+   locations in the virtual memory address space, one writable and one
+   executable.  Returns the address of the writable portion, after
+   storing an offset to the corresponding executable portion at the
+   last word of the requested chunk.  */
+static void *
+dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
+{
+  void *ptr;
+
+  if (execfd == -1)
+    {
+      open_temp_exec_file_opts_idx = 0;
+    retry_open:
+      execfd = open_temp_exec_file ();
+      if (execfd == -1)
+       return MFAIL;
+    }
+
+  offset = execsize;
+
+  if (ftruncate (execfd, offset + length))
+    return MFAIL;
+
+  flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
+  flags |= MAP_SHARED;
+
+  ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
+             flags, execfd, offset);
+  if (ptr == MFAIL)
+    {
+      if (!offset)
+       {
+         close (execfd);
+         goto retry_open;
+       }
+      ftruncate (execfd, offset);
+      return MFAIL;
+    }
+  else if (!offset
+          && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
+    open_temp_exec_file_opts_next ();
+
+  start = mmap (start, length, prot, flags, execfd, offset);
+
+  if (start == MFAIL)
+    {
+      munmap (ptr, length);
+      ftruncate (execfd, offset);
+      return start;
+    }
+
+  mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
+
+  execsize += length;
+
+  return start;
+}
+
+/* Map in a writable and executable chunk of memory if possible.
+   Failing that, fall back to dlmmap_locked.  */
+static void *
+dlmmap (void *start, size_t length, int prot,
+       int flags, int fd, off_t offset)
+{
+  void *ptr;
+
+  assert (start == NULL && length % malloc_getpagesize == 0
+         && prot == (PROT_READ | PROT_WRITE)
+         && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
+         && fd == -1 && offset == 0);
+
+#if FFI_CLOSURE_TEST
+  printf ("mapping in %zi\n", length);
+#endif
+
+  if (execfd == -1 && !is_selinux_enabled ())
+    {
+      ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
+
+      if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
+       /* Cool, no need to mess with separate segments.  */
+       return ptr;
+
+      /* If MREMAP_DUP is ever introduced and implemented, try mmap
+        with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
+        MREMAP_DUP and prot at this point.  */
+    }
+
+  if (execsize == 0 || execfd == -1)
+    {
+      pthread_mutex_lock (&open_temp_exec_file_mutex);
+      ptr = dlmmap_locked (start, length, prot, flags, offset);
+      pthread_mutex_unlock (&open_temp_exec_file_mutex);
+
+      return ptr;
+    }
+
+  return dlmmap_locked (start, length, prot, flags, offset);
+}
+
+/* Release memory at the given address, as well as the corresponding
+   executable page if it's separate.  */
+static int
+dlmunmap (void *start, size_t length)
+{
+  /* We don't bother decreasing execsize or truncating the file, since
+     we can't quite tell whether we're unmapping the end of the file.
+     We don't expect frequent deallocation anyway.  If we did, we
+     could locate pages in the file by writing to the pages being
+     deallocated and checking that the file contents change.
+     Yuck.  */
+  msegmentptr seg = segment_holding (gm, start);
+  void *code;
+
+#if FFI_CLOSURE_TEST
+  printf ("unmapping %zi\n", length);
+#endif
+
+  if (seg && (code = add_segment_exec_offset (start, seg)) != start)
+    {
+      int ret = munmap (code, length);
+      if (ret)
+       return ret;
+    }
+
+  return munmap (start, length);
+}
+
+#if FFI_CLOSURE_FREE_CODE
+/* Return segment holding given code address.  */
+static msegmentptr
+segment_holding_code (mstate m, char* addr)
+{
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= add_segment_exec_offset (sp->base, sp)
+       && addr < add_segment_exec_offset (sp->base, sp) + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+#endif
+
+/* Allocate a chunk of memory with the given size.  Returns a pointer
+   to the writable address, and sets *CODE to the executable
+   corresponding virtual address.  */
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+  void *ptr;
+
+  if (!code)
+    return NULL;
+
+  ptr = dlmalloc (size);
+
+  if (ptr)
+    {
+      msegmentptr seg = segment_holding (gm, ptr);
+
+      *code = add_segment_exec_offset (ptr, seg);
+    }
+
+  return ptr;
+}
+
+/* Release a chunk of memory allocated with ffi_closure_alloc.  If
+   FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
+   writable or the executable address given.  Otherwise, only the
+   writable address can be provided here.  */
+void
+ffi_closure_free (void *ptr)
+{
+#if FFI_CLOSURE_FREE_CODE
+  msegmentptr seg = segment_holding_code (gm, ptr);
+
+  if (seg)
+    ptr = sub_segment_exec_offset (ptr, seg);
+#endif
+
+  dlfree (ptr);
+}
+
+
+#if FFI_CLOSURE_TEST
+/* Do some internal sanity testing to make sure allocation and
+   deallocation of pages are working as intended.  */
+int main ()
+{
+  void *p[3];
+#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for 
p[%i]\n", (len), (idx)); } while (0)
+#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } 
while (0)
+  GET (0, malloc_getpagesize / 2);
+  GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
+  PUT (1);
+  GET (1, 2 * malloc_getpagesize);
+  GET (2, malloc_getpagesize / 2);
+  PUT (1);
+  PUT (0);
+  PUT (2);
+  return 0;
+}
+#endif /* FFI_CLOSURE_TEST */
+# else /* ! FFI_MMAP_EXEC_WRIT */
+
+/* On many systems, memory returned by malloc is writable and
+   executable, so just use it.  */
+
+#include <stdlib.h>
+
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+  if (!code)
+    return NULL;
+
+  return *code = malloc (size);
+}
+
+void
+ffi_closure_free (void *ptr)
+{
+  free (ptr);
+}
+
+# endif /* ! FFI_MMAP_EXEC_WRIT */
+#endif /* FFI_CLOSURES */

Index: libffi/src/dlmalloc.c
===================================================================
RCS file: libffi/src/dlmalloc.c
diff -N libffi/src/dlmalloc.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libffi/src/dlmalloc.c       30 Nov 2007 20:59:55 -0000      1.1
@@ -0,0 +1,5099 @@
+/*
+  This is a version (aka dlmalloc) of malloc/free/realloc written by
+  Doug Lea and released to the public domain, as explained at
+  http://creativecommons.org/licenses/publicdomain.  Send questions,
+  comments, complaints, performance data, etc to address@hidden
+
+* Version 2.8.3 Thu Sep 22 11:16:15 2005  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Quickstart
+
+  This library is all in one file to simplify the most common usage:
+  ftp it, compile it (-O3), and link it into another program. All of
+  the compile-time options default to reasonable values for use on
+  most platforms.  You might later want to step through various
+  compile-time and dynamic tuning options.
+
+  For convenience, an include file for code using this malloc is at:
+     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h
+  You don't really need this .h file unless you call functions not
+  defined in your system include files.  The .h file contains only the
+  excerpts from this file needed for using this malloc on ANSI C/C++
+  systems, so long as you haven't changed compile-time options about
+  naming and tuning parameters.  If you do, then you can create your
+  own malloc.h that does include all settings by cutting at the point
+  indicated below. Note that you may already by default be using a C
+  library containing a malloc that is based on some version of this
+  malloc (for example in linux). You might still want to use the one
+  in this file to customize settings or to avoid overheads associated
+  with library versions.
+
+* Vital statistics:
+
+  Supported pointer/size_t representation:       4 or 8 bytes
+       size_t MUST be an unsigned type of the same width as
+       pointers. (If you are using an ancient system that declares
+       size_t as a signed type, or need it to be a different width
+       than pointers, you can use a previous release of this malloc
+       (e.g. 2.7.2) supporting these.)
+
+  Alignment:                                     8 bytes (default)
+       This suffices for nearly all current machines and C compilers.
+       However, you can define MALLOC_ALIGNMENT to be wider than this
+       if necessary (up to 128bytes), at the expense of using more space.
+
+  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)
+                                          8 or 16 bytes (if 8byte sizes)
+       Each malloced chunk has a hidden word of overhead holding size
+       and status information, and additional cross-check word
+       if FOOTERS is defined.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)
+                          8-byte ptrs:  32 bytes    (including overhead)
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+       The maximum overhead wastage (i.e., number of extra bytes
+       allocated than were requested in malloc) is less than or equal
+       to the minimum size, except for requests >= mmap_threshold that
+       are serviced via mmap(), where the worst case wastage is about
+       32 bytes plus the remainder from a system page (the minimal
+       mmap unit); typically 4096 or 8192 bytes.
+
+  Security: static-safe; optionally more or less
+       The "security" of malloc refers to the ability of malicious
+       code to accentuate the effects of errors (for example, freeing
+       space that is not currently malloc'ed or overwriting past the
+       ends of chunks) in code that calls malloc.  This malloc
+       guarantees not to modify any memory locations below the base of
+       heap, i.e., static variables, even in the presence of usage
+       errors.  The routines additionally detect most improper frees
+       and reallocs.  All this holds as long as the static bookkeeping
+       for malloc itself is not corrupted by some other means.  This
+       is only one aspect of security -- these checks do not, and
+       cannot, detect all possible programming errors.
+
+       If FOOTERS is defined nonzero, then each allocated chunk
+       carries an additional check word to verify that it was malloced
+       from its space.  These check words are the same within each
+       execution of a program using malloc, but differ across
+       executions, so externally crafted fake chunks cannot be
+       freed. This improves security by rejecting frees/reallocs that
+       could corrupt heap memory, in addition to the checks preventing
+       writes to statics that are always on.  This may further improve
+       security at the expense of time and space overhead.  (Note that
+       FOOTERS may also be worth using with MSPACES.)
+
+       By default detected errors cause the program to abort (calling
+       "abort()"). You can override this to instead proceed past
+       errors by defining PROCEED_ON_ERROR.  In this case, a bad free
+       has no effect, and a malloc that encounters a bad address
+       caused by user overwrites will ignore the bad address by
+       dropping pointers and indices to all known memory. This may
+       be appropriate for programs that should continue if at all
+       possible in the face of programming errors, although they may
+       run out of memory because dropped memory is never reclaimed.
+
+       If you don't like either of these options, you can define
+       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
+       else. And if if you are sure that your program using malloc has
+       no errors or vulnerabilities, you can define INSECURE to 1,
+       which might (or might not) provide a small performance improvement.
+
+  Thread-safety: NOT thread-safe unless USE_LOCKS defined
+       When USE_LOCKS is defined, each public call to malloc, free,
+       etc is surrounded with either a pthread mutex or a win32
+       spinlock (depending on WIN32). This is not especially fast, and
+       can be a major bottleneck.  It is designed only to provide
+       minimal protection in concurrent environments, and to provide a
+       basis for extensions.  If you are using malloc in a concurrent
+       program, consider instead using ptmalloc, which is derived from
+       a version of this malloc. (See http://www.malloc.de).
+
+  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
+       This malloc can use unix sbrk or any emulation (invoked using
+       the CALL_MORECORE macro) and/or mmap/munmap or any emulation
+       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
+       memory.  On most unix systems, it tends to work best if both
+       MORECORE and MMAP are enabled.  On Win32, it uses emulations
+       based on VirtualAlloc. It also uses common C library functions
+       like memset.
+
+  Compliance: I believe it is compliant with the Single Unix Specification
+       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
+       others as well.
+
+* Overview of algorithms
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and
+  tunable.  Consistent balance across these factors results in a good
+  general-purpose allocator for malloc-intensive programs.
+
+  In most ways, this malloc is a best-fit allocator. Generally, it
+  chooses the best-fitting existing chunk for a request, with ties
+  broken in approximately least-recently-used order. (This strategy
+  normally maintains low fragmentation.) However, for requests less
+  than 256bytes, it deviates from best-fit when there is not an
+  exactly fitting available chunk by preferring to use space adjacent
+  to that used for the previous small request, as well as by breaking
+  ties in approximately most-recently-used order. (These enhance
+  locality of series of small allocations.)  And for very large requests
+  (>= 256Kb by default), it relies on system memory mapping
+  facilities, if supported.  (This helps avoid carrying around and
+  possibly fragmenting memory used only for large chunks.)
+
+  All operations (except malloc_stats and mallinfo) have execution
+  times that are bounded by a constant factor of the number of bits in
+  a size_t, not counting any clearing in calloc or copying in realloc,
+  or actions surrounding MORECORE and MMAP that have times
+  proportional to the number of non-contiguous regions returned by
+  system allocation routines, which is often just 1.
+
+  The implementation is not very modular and seriously overuses
+  macros. Perhaps someday all C compilers will do as good a job
+  inlining modular code as can now be done by brute-force expansion,
+  but now, enough of them seem not to.
+
+  Some compilers issue a lot of warnings about code that is
+  dead/unreachable only on some platforms, and also about intentional
+  uses of negation on unsigned types. All known cases of each can be
+  ignored.
+
+  For a longer but out of date high-level description, see
+     http://gee.cs.oswego.edu/dl/html/malloc.html
+
+* MSPACES
+  If MSPACES is defined, then in addition to malloc, free, etc.,
+  this file also defines mspace_malloc, mspace_free, etc. These
+  are versions of malloc routines that take an "mspace" argument
+  obtained using create_mspace, to control all internal bookkeeping.
+  If ONLY_MSPACES is defined, only these versions are compiled.
+  So if you would like to use this allocator for only some allocations,
+  and your system malloc for others, you can compile with
+  ONLY_MSPACES and then do something like...
+    static mspace mymspace = create_mspace(0,0); // for example
+    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)
+
+  (Note: If you only need one instance of an mspace, you can instead
+  use "USE_DL_PREFIX" to relabel the global malloc.)
+
+  You can similarly create thread-local allocators by storing
+  mspaces as thread-locals. For example:
+    static __thread mspace tlms = 0;
+    void*  tlmalloc(size_t bytes) {
+      if (tlms == 0) tlms = create_mspace(0, 0);
+      return mspace_malloc(tlms, bytes);
+    }
+    void  tlfree(void* mem) { mspace_free(tlms, mem); }
+
+  Unless FOOTERS is defined, each mspace is completely independent.
+  You cannot allocate from one and free to another (although
+  conformance is only weakly checked, so usage errors are not always
+  caught). If FOOTERS is defined, then each chunk carries around a tag
+  indicating its originating mspace, and frees are directed to their
+  originating spaces.
+
+ -------------------------  Compile-time options ---------------------------
+
+Be careful in setting #define values for numerical constants of type
+size_t. On some systems, literal values are not automatically extended
+to size_t precision unless they are explicitly casted.
+
+WIN32                    default: defined if _WIN32 defined
+  Defining WIN32 sets up defaults for MS environment and compilers.
+  Otherwise defaults are for unix.
+
+MALLOC_ALIGNMENT         default: (size_t)8
+  Controls the minimum alignment for malloc'ed chunks.  It must be a
+  power of two and at least 8, even on machines for which smaller
+  alignments would suffice. It may be defined as larger than this
+  though. Note however that code and data structures are optimized for
+  the case of 8-byte alignment.
+
+MSPACES                  default: 0 (false)
+  If true, compile in support for independent allocation spaces.
+  This is only supported if HAVE_MMAP is true.
+
+ONLY_MSPACES             default: 0 (false)
+  If true, only compile in mspace versions, not regular versions.
+
+USE_LOCKS                default: 0 (false)
+  Causes each call to each public routine to be surrounded with
+  pthread or WIN32 mutex lock/unlock. (If set true, this can be
+  overridden on a per-mspace basis for mspace versions.)
+
+FOOTERS                  default: 0
+  If true, provide extra checking and dispatching by placing
+  information in the footers of allocated chunks. This adds
+  space and time overhead.
+
+INSECURE                 default: 0
+  If true, omit checks for usage errors and heap space overwrites.
+
+USE_DL_PREFIX            default: NOT defined
+  Causes compiler to prefix all public routines with the string 'dl'.
+  This can be useful when you only want to use this malloc in one part
+  of a program, using your regular system malloc elsewhere.
+
+ABORT                    default: defined as abort()
+  Defines how to abort on failed checks.  On most systems, a failed
+  check cannot die with an "assert" or even print an informative
+  message, because the underlying print routines in turn call malloc,
+  which will fail again.  Generally, the best policy is to simply call
+  abort(). It's not very useful to do more than this because many
+  errors due to overwriting will show up as address faults (null, odd
+  addresses etc) rather than malloc-triggered checks, so will also
+  abort.  Also, most compilers know that abort() does not return, so
+  can better optimize code conditionally calling it.
+
+PROCEED_ON_ERROR           default: defined as 0 (false)
+  Controls whether detected bad addresses cause them to bypassed
+  rather than aborting. If set, detected bad arguments to free and
+  realloc are ignored. And all bookkeeping information is zeroed out
+  upon a detected overwrite of freed heap space, thus losing the
+  ability to ever return it from malloc again, but enabling the
+  application to proceed. If PROCEED_ON_ERROR is defined, the
+  static variable malloc_corruption_error_count is compiled in
+  and can be examined to see if errors have occurred. This option
+  generates slower code than the default abort policy.
+
+DEBUG                    default: NOT defined
+  The DEBUG setting is mainly intended for people trying to modify
+  this code or diagnose problems when porting to new platforms.
+  However, it may also be able to better isolate user errors than just
+  using runtime checks.  The assertions in the check routines spell
+  out in more detail the assumptions and invariants underlying the
+  algorithms.  The checking is fairly extensive, and will slow down
+  execution noticeably. Calling malloc_stats or mallinfo with DEBUG
+  set will attempt to check every non-mmapped allocated and free chunk
+  in the course of computing the summaries.
+
+ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)
+  Debugging assertion failures can be nearly impossible if your
+  version of the assert macro causes malloc to be called, which will
+  lead to a cascade of further failures, blowing the runtime stack.
+  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
+  which will usually make debugging easier.
+
+MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32
+  The action to take before "return 0" when malloc fails to be able to
+  return memory because there is none available.
+
+HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES
+  True if this system supports sbrk or an emulation of it.
+
+MORECORE                  default: sbrk
+  The name of the sbrk-style system routine to call to obtain more
+  memory.  See below for guidance on writing custom MORECORE
+  functions. The type of the argument to sbrk/MORECORE varies across
+  systems.  It cannot be size_t, because it supports negative
+  arguments, so it is normally the signed type of the same width as
+  size_t (sometimes declared as "intptr_t").  It doesn't much matter
+  though. Internally, we only call it with arguments less than half
+  the max value of a size_t, which should work across all reasonable
+  possibilities, although sometimes generating compiler warnings.  See
+  near the end of this file for guidelines for creating a custom
+  version of MORECORE.
+
+MORECORE_CONTIGUOUS       default: 1 (true)
+  If true, take advantage of fact that consecutive calls to MORECORE
+  with positive arguments always return contiguous increasing
+  addresses.  This is true of unix sbrk. It does not hurt too much to
+  set it true anyway, since malloc copes with non-contiguities.
+  Setting it false when definitely non-contiguous saves time
+  and possibly wasted space it would take to discover this though.
+
+MORECORE_CANNOT_TRIM      default: NOT defined
+  True if MORECORE cannot release space back to the system when given
+  negative arguments. This is generally necessary only if you are
+  using a hand-crafted MORECORE function that cannot handle negative
+  arguments.
+
+HAVE_MMAP                 default: 1 (true)
+  True if this system supports mmap or an emulation of it.  If so, and
+  HAVE_MORECORE is not true, MMAP is used for all system
+  allocation. If set and HAVE_MORECORE is true as well, MMAP is
+  primarily used to directly allocate very large blocks. It is also
+  used as a backup strategy in cases where MORECORE fails to provide
+  space from system. Note: A single call to MUNMAP is assumed to be
+  able to unmap memory that may have be allocated using multiple calls
+  to MMAP, so long as they are adjacent.
+
+HAVE_MREMAP               default: 1 on linux, else 0
+  If true realloc() uses mremap() to re-allocate large blocks and
+  extend or shrink allocation spaces.
+
+MMAP_CLEARS               default: 1 on unix
+  True if mmap clears memory so calloc doesn't need to. This is true
+  for standard unix mmap using /dev/zero.
+
+USE_BUILTIN_FFS            default: 0 (i.e., not used)
+  Causes malloc to use the builtin ffs() function to compute indices.
+  Some compilers may recognize and intrinsify ffs to be faster than the
+  supplied C version. Also, the case of x86 using gcc is special-cased
+  to an asm instruction, so is already as fast as it can be, and so
+  this setting has no effect. (On most x86s, the asm version is only
+  slightly faster than the C version.)
+
+malloc_getpagesize         default: derive from system includes, or 4096.
+  The system page size. To the extent possible, this malloc manages
+  memory from the system in page-size units.  This may be (and
+  usually is) a function rather than a constant. This is ignored
+  if WIN32, where page size is determined using getSystemInfo during
+  initialization.
+
+USE_DEV_RANDOM             default: 0 (i.e., not used)
+  Causes malloc to use /dev/random to initialize secure magic seed for
+  stamping footers. Otherwise, the current time is used.
+
+NO_MALLINFO                default: 0
+  If defined, don't compile "mallinfo". This can be a simple way
+  of dealing with mismatches between system declarations and
+  those in this file.
+
+MALLINFO_FIELD_TYPE        default: size_t
+  The type of the fields in the mallinfo struct. This was originally
+  defined as "int" in SVID etc, but is more usefully defined as
+  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
+
+REALLOC_ZERO_BYTES_FREES    default: not defined
+  This should be set if a call to realloc with zero bytes should 
+  be the same as a call to free. Some people think it should. Otherwise, 
+  since this malloc returns a unique pointer for malloc(0), so does 
+  realloc(p, 0).
+
+LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
+LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H
+LACKS_STDLIB_H                default: NOT defined unless on WIN32
+  Define these if your system does not have these header files.
+  You might need to manually insert some of the declarations they provide.
+
+DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,
+                                system_info.dwAllocationGranularity in WIN32,
+                                otherwise 64K.
+      Also settable using mallopt(M_GRANULARITY, x)
+  The unit for allocating and deallocating memory from the system.  On
+  most systems with contiguous MORECORE, there is no reason to
+  make this more than a page. However, systems with MMAP tend to
+  either require or encourage larger granularities.  You can increase
+  this value to prevent system allocation functions to be called so
+  often, especially if they are slow.  The value must be at least one
+  page and must be a power of two.  Setting to 0 causes initialization
+  to either page size or win32 region size.  (Note: In previous
+  versions of malloc, the equivalent of this option was called
+  "TOP_PAD")
+
+DEFAULT_TRIM_THRESHOLD    default: 2MB
+      Also settable using mallopt(M_TRIM_THRESHOLD, x)
+  The maximum amount of unused top-most memory to keep before
+  releasing via malloc_trim in free().  Automatic trimming is mainly
+  useful in long-lived programs using contiguous MORECORE.  Because
+  trimming via sbrk can be slow on some systems, and can sometimes be
+  wasteful (in cases where programs immediately afterward allocate
+  more large chunks) the value should be high enough so that your
+  overall system performance would improve by releasing this much
+  memory.  As a rough guide, you might set to a value close to the
+  average size of a process (program) running on your system.
+  Releasing this much memory would allow such a process to run in
+  memory.  Generally, it is worth tuning trim thresholds when a
+  program undergoes phases where several large chunks are allocated
+  and released in ways that can reuse each other's storage, perhaps
+  mixed with phases where there are no such chunks at all. The trim
+  value must be greater than page size to have any useful effect.  To
+  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
+  some people use of mallocing a huge space and then freeing it at
+  program startup, in an attempt to reserve system memory, doesn't
+  have the intended effect under automatic trimming, since that memory
+  will immediately be returned to the system.
+
+DEFAULT_MMAP_THRESHOLD       default: 256K
+      Also settable using mallopt(M_MMAP_THRESHOLD, x)
+  The request size threshold for using MMAP to directly service a
+  request. Requests of at least this size that cannot be allocated
+  using already-existing space will be serviced via mmap.  (If enough
+  normal freed space already exists it is used instead.)  Using mmap
+  segregates relatively large chunks of memory so that they can be
+  individually obtained and released from the host system. A request
+  serviced through mmap is never reused by any other request (at least
+  not directly; the system may just so happen to remap successive
+  requests to the same locations).  Segregating space in this way has
+  the benefits that: Mmapped space can always be individually released
+  back to the system, which helps keep the system level memory demands
+  of a long-lived program low.  Also, mapped memory doesn't become
+  `locked' between other chunks, as can happen with normally allocated
+  chunks, which means that even trimming via malloc_trim would not
+  release them.  However, it has the disadvantage that the space
+  cannot be reclaimed, consolidated, and then used to service later
+  requests, as happens with normal chunks.  The advantages of mmap
+  nearly always outweigh disadvantages for "large" chunks, but the
+  value of "large" may vary across systems.  The default is an
+  empirically derived value that works well in most systems. You can
+  disable mmap by setting to MAX_SIZE_T.
+
+*/
+
+#ifndef WIN32
+#ifdef _WIN32
+#define WIN32 1
+#endif  /* _WIN32 */
+#endif  /* WIN32 */
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define HAVE_MMAP 1
+#define HAVE_MORECORE 0
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+#define LACKS_STRING_H
+#define LACKS_STRINGS_H
+#define LACKS_SYS_TYPES_H
+#define LACKS_ERRNO_H
+#define MALLOC_FAILURE_ACTION
+#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */
+#endif  /* WIN32 */
+
+#if defined(DARWIN) || defined(_DARWIN)
+/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
+#ifndef HAVE_MORECORE
+#define HAVE_MORECORE 0
+#define HAVE_MMAP 1
+#endif  /* HAVE_MORECORE */
+#endif  /* DARWIN */
+
+#ifndef LACKS_SYS_TYPES_H
+#include <sys/types.h>  /* For size_t */
+#endif  /* LACKS_SYS_TYPES_H */
+
+/* The maximum possible size_t value has all bits set */
+#define MAX_SIZE_T           (~(size_t)0)
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0
+#endif  /* ONLY_MSPACES */
+#ifndef MSPACES
+#if ONLY_MSPACES
+#define MSPACES 1
+#else   /* ONLY_MSPACES */
+#define MSPACES 0
+#endif  /* ONLY_MSPACES */
+#endif  /* MSPACES */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif  /* MALLOC_ALIGNMENT */
+#ifndef FOOTERS
+#define FOOTERS 0
+#endif  /* FOOTERS */
+#ifndef ABORT
+#define ABORT  abort()
+#endif  /* ABORT */
+#ifndef ABORT_ON_ASSERT_FAILURE
+#define ABORT_ON_ASSERT_FAILURE 1
+#endif  /* ABORT_ON_ASSERT_FAILURE */
+#ifndef PROCEED_ON_ERROR
+#define PROCEED_ON_ERROR 0
+#endif  /* PROCEED_ON_ERROR */
+#ifndef USE_LOCKS
+#define USE_LOCKS 0
+#endif  /* USE_LOCKS */
+#ifndef INSECURE
+#define INSECURE 0
+#endif  /* INSECURE */
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif  /* HAVE_MMAP */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif  /* MMAP_CLEARS */
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else   /* linux */
+#define HAVE_MREMAP 0
+#endif  /* linux */
+#endif  /* HAVE_MREMAP */
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION  errno = ENOMEM;
+#endif  /* MALLOC_FAILURE_ACTION */
+#ifndef HAVE_MORECORE
+#if ONLY_MSPACES
+#define HAVE_MORECORE 0
+#else   /* ONLY_MSPACES */
+#define HAVE_MORECORE 1
+#endif  /* ONLY_MSPACES */
+#endif  /* HAVE_MORECORE */
+#if !HAVE_MORECORE
+#define MORECORE_CONTIGUOUS 0
+#else   /* !HAVE_MORECORE */
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif  /* MORECORE */
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* HAVE_MORECORE */
+#ifndef DEFAULT_GRANULARITY
+#if MORECORE_CONTIGUOUS
+#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */
+#else   /* MORECORE_CONTIGUOUS */
+#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* DEFAULT_GRANULARITY */
+#ifndef DEFAULT_TRIM_THRESHOLD
+#ifndef MORECORE_CANNOT_TRIM
+#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
+#else   /* MORECORE_CANNOT_TRIM */
+#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
+#endif  /* MORECORE_CANNOT_TRIM */
+#endif  /* DEFAULT_TRIM_THRESHOLD */
+#ifndef DEFAULT_MMAP_THRESHOLD
+#if HAVE_MMAP
+#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
+#else   /* HAVE_MMAP */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+#endif  /* HAVE_MMAP */
+#endif  /* DEFAULT_MMAP_THRESHOLD */
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 0
+#endif  /* USE_BUILTIN_FFS */
+#ifndef USE_DEV_RANDOM
+#define USE_DEV_RANDOM 0
+#endif  /* USE_DEV_RANDOM */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif  /* NO_MALLINFO */
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif  /* MALLINFO_FIELD_TYPE */
+
+/*
+  mallopt tuning options.  SVID/XPG defines four standard parameter
+  numbers for mallopt, normally defined in malloc.h.  None of these
+  are used in this malloc, so setting them has no effect. But this
+  malloc does support the following options.
+*/
+
+#define M_TRIM_THRESHOLD     (-1)
+#define M_GRANULARITY        (-2)
+#define M_MMAP_THRESHOLD     (-3)
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any system that has a
+  /usr/include/malloc.h defining struct mallinfo.  The main
+  declaration needed is the mallinfo struct that is returned (by-copy)
+  by mallinfo().  The malloinfo struct contains a bunch of fields that
+  are not even meaningful in this version of malloc.  These fields are
+  are instead filled by mallinfo() with other numbers that might be of
+  interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else a compliant version is
+  declared below.  These must be precisely the same for mallinfo() to
+  work.  The original SVID version of this struct, defined on most
+  systems with mallinfo, declares all fields as ints. But some others
+  define as unsigned long. If your system defines the fields using a
+  type of different width than listed here, you MUST #include your
+  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else /* HAVE_USR_INCLUDE_MALLOC_H */
+
+struct mallinfo {
+  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
+  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
+  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
+  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
+  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
+  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
+  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
+  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+  MALLINFO_FIELD_TYPE fordblks; /* total free space */
+  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* NO_MALLINFO */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if !ONLY_MSPACES
+
+/* ------------------- Declarations of public routines ------------------- */
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc               calloc
+#define dlfree                 free
+#define dlmalloc               malloc
+#define dlmemalign             memalign
+#define dlrealloc              realloc
+#define dlvalloc               valloc
+#define dlpvalloc              pvalloc
+#define dlmallinfo             mallinfo
+#define dlmallopt              mallopt
+#define dlmalloc_trim          malloc_trim
+#define dlmalloc_stats         malloc_stats
+#define dlmalloc_usable_size   malloc_usable_size
+#define dlmalloc_footprint     malloc_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc   independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+  malloc(size_t n)
+  Returns a pointer to a newly allocated chunk of at least n bytes, or
+  null if no space is available, in which case errno is set to ENOMEM
+  on ANSI C systems.
+
+  If n is zero, malloc returns a minimum-sized chunk. (The minimum
+  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+  systems.)  Note that size_t is an unsigned type, so calls with
+  arguments that would be negative if signed are interpreted as
+  requests for huge amounts of space, which will often fail. The
+  maximum supported value of n differs across systems, but is in all
+  cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+  free(void* p)
+  Releases the chunk of memory pointed to by p, that had been previously
+  allocated using malloc or a related routine such as realloc.
+  It has no effect if p is null. If p was not malloced or already
+  freed, free(p) will by default cause the current program to abort.
+*/
+void  dlfree(void*);
+
+/*
+  calloc(size_t n_elements, size_t element_size);
+  Returns a pointer to n_elements * element_size bytes, with all locations
+  set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+  realloc(void* p, size_t n)
+  Returns a pointer to a chunk of size n that contains the same data
+  as does chunk p up to the minimum of (n, p's size) bytes, or null
+  if no space is available.
+
+  The returned pointer may or may not be the same as p. The algorithm
+  prefers extending p in most cases when possible, otherwise it
+  employs the equivalent of a malloc-copy-free sequence.
+
+  If p is null, realloc is equivalent to malloc.
+
+  If space is not available, realloc returns null, errno is set (if on
+  ANSI) and p is NOT freed.
+
+  if n is for fewer bytes than already held by p, the newly unused
+  space is lopped off and freed if possible.  realloc with a size
+  argument of zero (re)allocates a minimum-sized chunk.
+
+  The old unix realloc convention of allowing the last-free'd chunk
+  to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+  memalign(size_t alignment, size_t n);
+  Returns a pointer to a newly allocated chunk of n bytes, aligned
+  in accord with the alignment argument.
+
+  The alignment argument should be a power of two. If the argument is
+  not a power of two, the nearest greater power is used.
+  8-byte alignment is guaranteed by normal malloc calls, so don't
+  bother calling memalign with an argument of 8 or less.
+
+  Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+  valloc(size_t n);
+  Equivalent to memalign(pagesize, n), where pagesize is the page
+  size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+  mallopt(int parameter_number, int parameter_value)
+  Sets tunable parameters The format is to provide a
+  (parameter-number, parameter-value) pair.  mallopt then sets the
+  corresponding parameter to the argument value if it can (i.e., so
+  long as the value is meaningful), and returns 1 if successful else
+  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
+  normally defined in malloc.h.  None of these are use in this malloc,
+  so setting them has no effect. But this malloc also supports other
+  options in mallopt. See below for details.  Briefly, supported
+  parameters are as follows (listed defaults are for "typical"
+  configurations).
+
+  Symbol            param #  default    allowed param values
+  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (MAX_SIZE_T disables)
+  M_GRANULARITY        -2     page size   any power of 2 >= page size
+  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+/*
+  malloc_footprint();
+  Returns the number of bytes obtained from the system.  The total
+  number of bytes allocated by malloc, realloc etc., is less than this
+  value. Unlike mallinfo, this function returns only a precomputed
+  result, so can be called frequently to monitor memory consumption.
+  Even if locks are otherwise defined, this function does not use them,
+  so results might not be up to date.
+*/
+size_t dlmalloc_footprint(void);
+
+/*
+  malloc_max_footprint();
+  Returns the maximum number of bytes obtained from the system. This
+  value will be greater than current footprint if deallocated space
+  has been reclaimed by the system. The peak number of bytes allocated
+  by malloc, realloc etc., is less than this value. Unlike mallinfo,
+  this function returns only a precomputed result, so can be called
+  frequently to monitor memory consumption.  Even if locks are
+  otherwise defined, this function does not use them, so results might
+  not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+  mallinfo()
+  Returns (by copy) a struct containing various summary statistics:
+
+  arena:     current total non-mmapped bytes allocated from system
+  ordblks:   the number of free chunks
+  smblks:    always zero.
+  hblks:     current number of mmapped regions
+  hblkhd:    total bytes held in mmapped regions
+  usmblks:   the maximum total allocated space. This will be greater
+                than current total if trimming has occurred.
+  fsmblks:   always zero
+  uordblks:  current total allocated space (normal or mmapped)
+  fordblks:  total free space
+  keepcost:  the maximum number of bytes that could ideally be released
+               back to system via malloc_trim. ("ideally" means that
+               it ignores page restrictions etc.)
+
+  Because these fields are ints, but internal bookkeeping may
+  be kept as longs, the reported values may wrap around zero and
+  thus be inaccurate.
+*/
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+  independent_calloc is similar to calloc, but instead of returning a
+  single cleared space, it returns an array of pointers to n_elements
+  independent elements that can hold contents of size elem_size, each
+  of which starts out cleared, and can be independently freed,
+  realloc'ed etc. The elements are guaranteed to be adjacently
+  allocated (this is not guaranteed to occur with multiple callocs or
+  mallocs), which may also improve cache locality in some
+  applications.
+
+  The "chunks" argument is optional (i.e., may be null, which is
+  probably the most typical usage). If it is null, the returned array
+  is itself dynamically allocated and should also be freed when it is
+  no longer needed. Otherwise, the chunks array must be of at least
+  n_elements in length. It is filled in with the pointers to the
+  chunks.
+
+  In either case, independent_calloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and "chunks"
+  is null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use regular calloc and assign pointers into this
+  space to represent elements.  (In this case though, you cannot
+  independently free elements.)
+
+  independent_calloc simplifies and speeds up implementations of many
+  kinds of pools.  It may also be useful when constructing large data
+  structures that initially have a fixed number of fixed-sized nodes,
+  but the number is not known at compile time, and some of the nodes
+  may later need to be freed. For example:
+
+  struct Node { int item; struct Node* next; };
+
+  struct Node* build_list() {
+    struct Node** pool;
+    int n = read_number_of_nodes_needed();
+    if (n <= 0) return 0;
+    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+    if (pool == 0) die();
+    // organize into a linked list...
+    struct Node* first = pool[0];
+    for (i = 0; i < n-1; ++i)
+      pool[i]->next = pool[i+1];
+    free(pool);     // Can now free the array (or not, if it is needed later)
+    return first;
+  }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+  independent_comalloc allocates, all at once, a set of n_elements
+  chunks with sizes indicated in the "sizes" array.    It returns
+  an array of pointers to these elements, each of which can be
+  independently freed, realloc'ed etc. The elements are guaranteed to
+  be adjacently allocated (this is not guaranteed to occur with
+  multiple callocs or mallocs), which may also improve cache locality
+  in some applications.
+
+  The "chunks" argument is optional (i.e., may be null). If it is null
+  the returned array is itself dynamically allocated and should also
+  be freed when it is no longer needed. Otherwise, the chunks array
+  must be of at least n_elements in length. It is filled in with the
+  pointers to the chunks.
+
+  In either case, independent_comalloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and chunks is
+  null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use a single regular malloc, and assign pointers at
+  particular offsets in the aggregate space. (In this case though, you
+  cannot independently free elements.)
+
+  independent_comallac differs from independent_calloc in that each
+  element may have a different size, and also that it does not
+  automatically clear elements.
+
+  independent_comalloc can be used to speed up allocation in cases
+  where several structs or objects must always be allocated at the
+  same time.  For example:
+
+  struct Head { ... }
+  struct Foot { ... }
+
+  void send_message(char* msg) {
+    int msglen = strlen(msg);
+    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+    void* chunks[3];
+    if (independent_comalloc(3, sizes, chunks) == 0)
+      die();
+    struct Head* head = (struct Head*)(chunks[0]);
+    char*        body = (char*)(chunks[1]);
+    struct Foot* foot = (struct Foot*)(chunks[2]);
+    // ...
+  }
+
+  In general though, independent_comalloc is worth using only for
+  larger values of n_elements. For small values, you probably won't
+  detect enough difference from series of malloc calls to bother.
+
+  Overuse of independent_comalloc can increase overall memory usage,
+  since it cannot reuse existing noncontiguous small chunks that
+  might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+  pvalloc(size_t n);
+  Equivalent to valloc(minimum-page-that-holds(n)), that is,
+  round up n to nearest pagesize.
+ */
+void*  dlpvalloc(size_t);
+
+/*
+  malloc_trim(size_t pad);
+
+  If possible, gives memory back to the system (via negative arguments
+  to sbrk) if there is unused memory at the `high' end of the malloc
+  pool or in unused MMAP segments. You can call this after freeing
+  large blocks of memory to potentially reduce the system-level memory
+  requirements of a program. However, it cannot guarantee to reduce
+  memory. Under some allocation patterns, some large free blocks of
+  memory will be locked between two used chunks, so they cannot be
+  given back to the system.
+
+  The `pad' argument to malloc_trim represents the amount of free
+  trailing space to leave untrimmed. If this argument is zero, only
+  the minimum amount of memory to maintain internal data structures
+  will be left. Non-zero arguments can be supplied to maintain enough
+  trailing space to service future expected allocations without having
+  to re-obtain memory from the system.
+
+  Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int  dlmalloc_trim(size_t);
+
+/*
+  malloc_usable_size(void* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. malloc_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = malloc(n);
+  assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+/*
+  malloc_stats();
+  Prints on stderr the amount of space obtained from the system (both
+  via sbrk and mmap), the maximum amount (which may be more than
+  current if malloc_trim and/or munmap got called), and the current
+  number of bytes allocated via malloc (or realloc, etc) but not yet
+  freed. Note that this is the number of bytes allocated, not the
+  number requested. It will be larger than the number requested
+  because of alignment and bookkeeping overhead. Because it includes
+  alignment wastage as being in use, this figure may be greater than
+  zero even when no user-level chunks are allocated.
+
+  The reported current and maximum system memory can be inaccurate if
+  a program makes other calls to system memory allocation functions
+  (normally sbrk) outside of malloc.
+
+  malloc_stats prints only the most commonly interesting statistics.
+  More information can be obtained by calling mallinfo.
+*/
+void  dlmalloc_stats(void);
+
+#endif /* ONLY_MSPACES */
+
+#if MSPACES
+
+/*
+  mspace is an opaque type representing an independent
+  region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+  create_mspace creates and returns a new independent space with the
+  given initial capacity, or, if 0, the default granularity size.  It
+  returns null if there is no system memory available to create the
+  space.  If argument locked is non-zero, the space uses a separate
+  lock to control access. The capacity of the space will grow
+  dynamically as needed to service mspace_malloc requests.  You can
+  control the sizes of incremental increases of this space by
+  compiling with a different DEFAULT_GRANULARITY or dynamically
+  setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+  destroy_mspace destroys the given space, and attempts to return all
+  of its memory back to the system, returning the total number of
+  bytes freed. After destruction, the results of access to all memory
+  used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+  create_mspace_with_base uses the memory supplied as the initial base
+  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+  space is used for bookkeeping, so the capacity must be at least this
+  large. (Otherwise 0 is returned.) When this initial space is
+  exhausted, additional memory will be obtained from the system.
+  Destroying this space will deallocate all additionally allocated
+  space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+  mspace_malloc behaves as malloc, but operates within
+  the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+  mspace_free behaves as free, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_free is not actually needed.
+  free may be called instead of mspace_free because freed chunks from
+  any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+  mspace_realloc behaves as realloc, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_realloc is not actually
+  needed.  realloc may be called instead of mspace_realloc because
+  realloced chunks from any space are handled by their originating
+  spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+  mspace_calloc behaves as calloc, but operates within
+  the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+  mspace_memalign behaves as memalign, but operates within
+  the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+  mspace_independent_calloc behaves as independent_calloc, but
+  operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+                                 size_t elem_size, void* chunks[]);
+
+/*
+  mspace_independent_comalloc behaves as independent_comalloc, but
+  operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+                                   size_t sizes[], void* chunks[]);
+
+/*
+  mspace_footprint() returns the number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+  mspace_max_footprint() returns the peak number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+  mspace_mallinfo behaves as mallinfo, but reports properties of
+  the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+  mspace_malloc_stats behaves as malloc_stats, but reports
+  properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+  mspace_trim behaves as malloc_trim, but
+  operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+  An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif /* __cplusplus */
+
+/*
+  ========================================================================
+  To make a fully customizable malloc.h header file, cut everything
+  above this line, put into file malloc.h, edit to suit, and #include it
+  on the next line, as well as in programs that use this malloc.
+  ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/*------------------------------ internal #includes ---------------------- */
+
+#ifdef WIN32
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+#endif /* WIN32 */
+
+#include <stdio.h>       /* for printing in malloc_stats */
+
+#ifndef LACKS_ERRNO_H
+#include <errno.h>       /* for MALLOC_FAILURE_ACTION */
+#endif /* LACKS_ERRNO_H */
+#if FOOTERS
+#include <time.h>        /* for magic initialization */
+#endif /* FOOTERS */
+#ifndef LACKS_STDLIB_H
+#include <stdlib.h>      /* for abort() */
+#endif /* LACKS_STDLIB_H */
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#define assert(x) if(!(x)) ABORT
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else  /* DEBUG */
+#define assert(x)
+#endif /* DEBUG */
+#ifndef LACKS_STRING_H
+#include <string.h>      /* for memset etc */
+#endif  /* LACKS_STRING_H */
+#if USE_BUILTIN_FFS
+#ifndef LACKS_STRINGS_H
+#include <strings.h>     /* for ffs */
+#endif /* LACKS_STRINGS_H */
+#endif /* USE_BUILTIN_FFS */
+#if HAVE_MMAP
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>    /* for mmap */
+#endif /* LACKS_SYS_MMAN_H */
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif /* LACKS_FCNTL_H */
+#endif /* HAVE_MMAP */
+#if HAVE_MORECORE
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>     /* for sbrk */
+#else /* LACKS_UNISTD_H */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+extern void*     sbrk(ptrdiff_t);
+#endif /* FreeBSD etc */
+#endif /* LACKS_UNISTD_H */
+#endif /* HAVE_MMAP */
+
+#ifndef WIN32
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32 /* use supplied emulation of getpagesize */
+#        define malloc_getpagesize getpagesize()
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else /* just guess */
+#                define malloc_getpagesize ((size_t)4096U)
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+#endif
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE         (sizeof(size_t))
+#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some plaftorms */
+#define SIZE_T_ZERO         ((size_t)0)
+#define SIZE_T_ONE          ((size_t)1)
+#define SIZE_T_TWO          ((size_t)2)
+#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* -------------------------- MMAP preliminaries ------------------------- */
+
+/*
+   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
+   checks to fail so compiler optimizer can delete code rather than
+   using so many "#if"s.
+*/
+
+
+/* MORECORE and MMAP must return MFAIL on failure */
+#define MFAIL                ((void*)(MAX_SIZE_T))
+#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */
+
+#if !HAVE_MMAP
+#define IS_MMAPPED_BIT       (SIZE_T_ZERO)
+#define USE_MMAP_BIT         (SIZE_T_ZERO)
+#define CALL_MMAP(s)         MFAIL
+#define CALL_MUNMAP(a, s)    (-1)
+#define DIRECT_MMAP(s)       MFAIL
+
+#else /* HAVE_MMAP */
+#define IS_MMAPPED_BIT       (SIZE_T_ONE)
+#define USE_MMAP_BIT         (SIZE_T_ONE)
+
+#ifndef WIN32
+#define CALL_MUNMAP(a, s)    munmap((a), (s))
+#define MMAP_PROT            (PROT_READ|PROT_WRITE)
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS        MAP_ANON
+#endif /* MAP_ANON */
+#ifdef MAP_ANONYMOUS
+#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)
+#define CALL_MMAP(s)         mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
+#else /* MAP_ANONYMOUS */
+/*
+   Nearly all versions of mmap support MAP_ANONYMOUS, so the following
+   is unlikely to be needed, but is supplied just in case.
+*/
+#define MMAP_FLAGS           (MAP_PRIVATE)
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \
+           (dev_zero_fd = open("/dev/zero", O_RDWR), \
+            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
+            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
+#endif /* MAP_ANONYMOUS */
+
+#define DIRECT_MMAP(s)       CALL_MMAP(s)
+#else /* WIN32 */
+
+/* Win32 MMAP via VirtualAlloc */
+static void* win32mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
+static void* win32direct_mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
+                           PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* This function supports releasing coalesed segments */
+static int win32munmap(void* ptr, size_t size) {
+  MEMORY_BASIC_INFORMATION minfo;
+  char* cptr = ptr;
+  while (size) {
+    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
+      return -1;
+    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
+        minfo.State != MEM_COMMIT || minfo.RegionSize > size)
+      return -1;
+    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
+      return -1;
+    cptr += minfo.RegionSize;
+    size -= minfo.RegionSize;
+  }
+  return 0;
+}
+
+#define CALL_MMAP(s)         win32mmap(s)
+#define CALL_MUNMAP(a, s)    win32munmap((a), (s))
+#define DIRECT_MMAP(s)       win32direct_mmap(s)
+#endif /* WIN32 */
+#endif /* HAVE_MMAP */
+
+#if HAVE_MMAP && HAVE_MREMAP
+#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
+#else  /* HAVE_MMAP && HAVE_MREMAP */
+#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
+#endif /* HAVE_MMAP && HAVE_MREMAP */
+
+#if HAVE_MORECORE
+#define CALL_MORECORE(S)     MORECORE(S)
+#else  /* HAVE_MORECORE */
+#define CALL_MORECORE(S)     MFAIL
+#endif /* HAVE_MORECORE */
+
+/* mstate bit set if continguous morecore disabled or failed */
+#define USE_NONCONTIGUOUS_BIT (4U)
+
+/* segment bit set in create_mspace_with_base */
+#define EXTERN_BIT            (8U)
+
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+#if USE_LOCKS
+
+/*
+  When locks are defined, there are up to two global locks:
+
+  * If HAVE_MORECORE, morecore_mutex protects sequences of calls to
+    MORECORE.  In many cases sys_alloc requires two calls, that should
+    not be interleaved with calls by other threads.  This does not
+    protect against direct calls to MORECORE by other threads not
+    using this lock, so there is still code to cope the best we can on
+    interference.
+
+  * magic_init_mutex ensures that mparams.magic and other
+    unique mparams values are initialized only once.
+*/
+
+#ifndef WIN32
+/* By default use posix locks */
+#include <pthread.h>
+#define MLOCK_T pthread_mutex_t
+#define INITIAL_LOCK(l)      pthread_mutex_init(l, NULL)
+#define ACQUIRE_LOCK(l)      pthread_mutex_lock(l)
+#define RELEASE_LOCK(l)      pthread_mutex_unlock(l)
+
+#if HAVE_MORECORE
+static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif /* HAVE_MORECORE */
+
+static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#else /* WIN32 */
+/*
+   Because lock-protected regions have bounded times, and there
+   are no recursive lock calls, we can use simple spinlocks.
+*/
+
+#define MLOCK_T long
+static int win32_acquire_lock (MLOCK_T *sl) {
+  for (;;) {
+#ifdef InterlockedCompareExchangePointer
+    if (!InterlockedCompareExchange(sl, 1, 0))
+      return 0;
+#else  /* Use older void* version */
+    if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0))
+      return 0;
+#endif /* InterlockedCompareExchangePointer */
+    Sleep (0);
+  }
+}
+
+static void win32_release_lock (MLOCK_T *sl) {
+  InterlockedExchange (sl, 0);
+}
+
+#define INITIAL_LOCK(l)      *(l)=0
+#define ACQUIRE_LOCK(l)      win32_acquire_lock(l)
+#define RELEASE_LOCK(l)      win32_release_lock(l)
+#if HAVE_MORECORE
+static MLOCK_T morecore_mutex;
+#endif /* HAVE_MORECORE */
+static MLOCK_T magic_init_mutex;
+#endif /* WIN32 */
+
+#define USE_LOCK_BIT               (2U)
+#else  /* USE_LOCKS */
+#define USE_LOCK_BIT               (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS && HAVE_MORECORE
+#define ACQUIRE_MORECORE_LOCK()    ACQUIRE_LOCK(&morecore_mutex);
+#define RELEASE_MORECORE_LOCK()    RELEASE_LOCK(&morecore_mutex);
+#else /* USE_LOCKS && HAVE_MORECORE */
+#define ACQUIRE_MORECORE_LOCK()
+#define RELEASE_MORECORE_LOCK()
+#endif /* USE_LOCKS && HAVE_MORECORE */
+
+#if USE_LOCKS
+#define ACQUIRE_MAGIC_INIT_LOCK()  ACQUIRE_LOCK(&magic_init_mutex);
+#define RELEASE_MAGIC_INIT_LOCK()  RELEASE_LOCK(&magic_init_mutex);
+#else  /* USE_LOCKS */
+#define ACQUIRE_MAGIC_INIT_LOCK()
+#define RELEASE_MAGIC_INIT_LOCK()
+#endif /* USE_LOCKS */
+
+
+/* -----------------------  Chunk representations ------------------------ */
+
+/*
+  (The following includes lightly edited explanations by Colin Plumb.)
+
+  The malloc_chunk declaration below is misleading (but accurate and
+  necessary).  It declares a "view" into memory allowing access to
+  necessary fields at known offsets from a given base.
+
+  Chunks of memory are maintained using a `boundary tag' method as
+  originally described by Knuth.  (See the paper by Paul Wilson
+  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+  techniques.)  Sizes of free chunks are stored both in the front of
+  each chunk and at the end.  This makes consolidating fragmented
+  chunks into bigger chunks fast.  The head fields also hold bits
+  representing whether chunks are free or in use.
+
+  Here are some pictures to make it clearer.  They are "exploded" to
+  show that the state of a chunk can be thought of as extending from
+  the high 31 bits of the head field of its header through the
+  prev_foot and PINUSE_BIT bit of the following chunk header.
+
+  A chunk that's in use looks like:
+
+   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           | Size of previous chunk (if P = 1)                             |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         1| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               |
+         +-                                                             -+
+         |                                                               |
+         +-                                                             -+
+         |                                                               :
+         +-      size - sizeof(size_t) available payload bytes          -+
+         :                                                               |
+ chunk-> +-                                                             -+
+         |                                                               |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+       | Size of next chunk (may or may not be in use)               | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    And if it's free, it looks like this:
+
+   chunk-> +-                                                             -+
+           | User payload (must be in use, or we would have merged!)       |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         0| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Next pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Prev pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               :
+         +-      size - sizeof(struct chunk) unused bytes               -+
+         :                                                               |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Size of this chunk                                            |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+       | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                                                               :
+       +- User payload                                                -+
+       :                                                               |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                                                     |0|
+                                                                     +-+
+  Note that since we always merge adjacent free chunks, the chunks
+  adjacent to a free chunk must be in use.
+
+  Given a pointer to a chunk (which can be derived trivially from the
+  payload pointer) we can, in O(1) time, find out whether the adjacent
+  chunks are free, and if so, unlink them from the lists that they
+  are on and merge them with the current chunk.
+
+  Chunks always begin on even word boundaries, so the mem portion
+  (which is returned to the user) is also on an even word boundary, and
+  thus at least double-word aligned.
+
+  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+  chunk size (which is always a multiple of two words), is an in-use
+  bit for the *previous* chunk.  If that bit is *clear*, then the
+  word before the current chunk size contains the previous chunk
+  size, and can be used to find the front of the previous chunk.
+  The very first chunk allocated always has this bit set, preventing
+  access to non-existent (or non-owned) memory. If pinuse is set for
+  any given chunk, then you CANNOT determine the size of the
+  previous chunk, and might even get a memory addressing fault when
+  trying to do so.
+
+  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+  the chunk size redundantly records whether the current chunk is
+  inuse. This redundancy enables usage checks within free and realloc,
+  and reduces indirection when freeing and consolidating chunks.
+
+  Each freshly allocated chunk must have both cinuse and pinuse set.
+  That is, each allocated chunk borders either a previously allocated
+  and still in-use chunk, or the base of its memory arena. This is
+  ensured by making all allocations from the the `lowest' part of any
+  found chunk.  Further, no free chunk physically borders another one,
+  so each free chunk is known to be preceded and followed by either
+  inuse chunks or the ends of memory.
+
+  Note that the `foot' of the current chunk is actually represented
+  as the prev_foot of the NEXT chunk. This makes it easier to
+  deal with alignments etc but can be very confusing when trying
+  to extend or adapt this code.
+
+  The exceptions to all this are
+
+     1. The special chunk `top' is the top-most available chunk (i.e.,
+        the one bordering the end of available memory). It is treated
+        specially.  Top is never included in any bin, is used only if
+        no other chunk is available, and is released back to the
+        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
+        the top chunk is treated as larger (and thus less well
+        fitting) than any other available chunk.  The top chunk
+        doesn't update its trailing size field since there is no next
+        contiguous chunk that would have to index off it. However,
+        space is still allocated for it (TOP_FOOT_SIZE) to enable
+        separation or merging when space is extended.
+
+     3. Chunks allocated via mmap, which have the lowest-order bit
+        (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
+        PINUSE_BIT in their head fields.  Because they are allocated
+        one-by-one, each must carry its own prev_foot field, which is
+        also used to hold the offset this chunk has within its mmapped
+        region, which is needed to preserve alignment. Each mmapped
+        chunk is trailed by the first two fields of a fake next-chunk
+        for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+  size_t               prev_foot;  /* Size of previous chunk (if free).  */
+  size_t               head;       /* Size and inuse bits. */
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk  mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
+typedef unsigned int bindex_t;         /* Described below */
+typedef unsigned int binmap_t;         /* Described below */
+typedef unsigned int flag_t;           /* The type of various bit flag sets */
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE         (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* MMapped chunks need a second word of overhead ... */
+#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+/* ... and additional padding for fake next-chunk at foot */
+#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+  The head field of a chunk is or'ed with PINUSE_BIT when previous
+  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+  use. If the chunk was obtained with mmap, the prev_foot field has
+  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
+  mmapped region to the base of the chunk.
+*/
+
+#define PINUSE_BIT          (SIZE_T_ONE)
+#define CINUSE_BIT          (SIZE_T_TWO)
+#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p)           ((p)->head & CINUSE_BIT)
+#define pinuse(p)           ((p)->head & PINUSE_BIT)
+#define chunksize(p)        ((p)->head & ~(INUSE_BITS))
+
+#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
+#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+#define is_mmapped(p)\
+  (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p)\
+ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
+
+/* Return true if malloced space is not necessarily cleared */
+#if MMAP_CLEARS
+#define calloc_must_clear(p) (!is_mmapped(p))
+#else /* MMAP_CLEARS */
+#define calloc_must_clear(p) (1)
+#endif /* MMAP_CLEARS */
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+  When chunks are not in use, they are treated as nodes of either
+  lists or trees.
+
+  "Small"  chunks are stored in circular doubly-linked lists, and look
+  like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Larger chunks are kept in a form of bitwise digital trees (aka
+  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
+  free chunks greater than 256 bytes, their size doesn't impose any
+  constraints on user chunk sizes.  Each node looks like:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk of same size        |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk of same size       |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to left child (child[0])                  |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to right child (child[1])                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to parent                                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             bin index of this chunk                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space                                      .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
+  of the same size are arranged in a circularly-linked list, with only
+  the oldest chunk (the next to be used, in our FIFO ordering)
+  actually in the tree.  (Tree members are distinguished by a non-null
+  parent pointer.)  If a chunk with the same size an an existing node
+  is inserted, it is linked off the existing node using pointers that
+  work in the same way as fd/bk pointers of small chunks.
+
+  Each tree contains a power of 2 sized range of chunk sizes (the
+  smallest is 0x100 <= x < 0x180), which is is divided in half at each
+  tree level, with the chunks in the smaller half of the range (0x100
+  <= x < 0x140 for the top nose) in the left subtree and the larger
+  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
+  done by inspecting individual bits.
+
+  Using these rules, each node's left subtree contains all smaller
+  sizes than its right subtree.  However, the node at the root of each
+  subtree has no particular ordering relationship to either.  (The
+  dividing line between the subtree sizes is based on trie relation.)
+  If we remove the last chunk of a given size from the interior of the
+  tree, we need to replace it with a leaf node.  The tree ordering
+  rules permit a node to be replaced by any leaf below it.
+
+  The smallest chunk in a tree (a common operation in a best-fit
+  allocator) can be found by walking a path to the leftmost leaf in
+  the tree.  Unlike a usual binary tree, where we follow left child
+  pointers until we reach a null, here we follow the right child
+  pointer any time the left one is null, until we reach a leaf with
+  both child pointers null. The smallest chunk in the tree will be
+  somewhere along that path.
+
+  The worst case number of steps to add, find, or remove a node is
+  bounded by the number of bits differentiating chunks within
+  bins. Under current bin calculations, this ranges from 6 up to 21
+  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+  is of course much better.
+*/
+
+struct malloc_tree_chunk {
+  /* The first four fields must be compatible with malloc_chunk */
+  size_t                    prev_foot;
+  size_t                    head;
+  struct malloc_tree_chunk* fd;
+  struct malloc_tree_chunk* bk;
+
+  struct malloc_tree_chunk* child[2];
+  struct malloc_tree_chunk* parent;
+  bindex_t                  index;
+};
+
+typedef struct malloc_tree_chunk  tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+  Each malloc space may include non-contiguous segments, held in a
+  list headed by an embedded malloc_segment record representing the
+  top-most space. Segments also include flags holding properties of
+  the space. Large chunks that are directly allocated by mmap are not
+  included in this list. They are instead independently created and
+  destroyed without otherwise keeping track of them.
+
+  Segment management mainly comes into play for spaces allocated by
+  MMAP.  Any call to MMAP might or might not return memory that is
+  adjacent to an existing segment.  MORECORE normally contiguously
+  extends the current space, so this space is almost always adjacent,
+  which is simpler and faster to deal with. (This is why MORECORE is
+  used preferentially to MMAP when both are available -- see
+  sys_alloc.)  When allocating using MMAP, we don't use any of the
+  hinting mechanisms (inconsistently) supported in various
+  implementations of unix mmap, or distinguish reserving from
+  committing memory. Instead, we just ask for space, and exploit
+  contiguity when we get it.  It is probably possible to do
+  better than this on some systems, but no general scheme seems
+  to be significantly better.
+
+  Management entails a simpler variant of the consolidation scheme
+  used for chunks to reduce fragmentation -- new adjacent memory is
+  normally prepended or appended to an existing segment. However,
+  there are limitations compared to chunk consolidation that mostly
+  reflect the fact that segment processing is relatively infrequent
+  (occurring only when getting memory from system) and that we
+  don't expect to have huge numbers of segments:
+
+  * Segments are not indexed, so traversal requires linear scans.  (It
+    would be possible to index these, but is not worth the extra
+    overhead and complexity for most programs on most platforms.)
+  * New segments are only appended to old ones when holding top-most
+    memory; if they cannot be prepended to others, they are held in
+    different segments.
+
+  Except for the top-most segment of an mstate, each segment record
+  is kept at the tail of its segment. Segments are added by pushing
+  segment records onto the list headed by &mstate.seg for the
+  containing mstate.
+
+  Segment flags control allocation/merge/deallocation policies:
+  * If EXTERN_BIT set, then we did not allocate this segment,
+    and so should not try to deallocate or merge with others.
+    (This currently holds only for the initial segment passed
+    into create_mspace_with_base.)
+  * If IS_MMAPPED_BIT set, the segment may be merged with
+    other surrounding mmapped segments and trimmed/de-allocated
+    using munmap.
+  * If neither bit is set, then the segment was obtained using
+    MORECORE so can be merged with surrounding MORECORE'd segments
+    and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+  char*        base;             /* base address */
+  size_t       size;             /* allocated size */
+  struct malloc_segment* next;   /* ptr to next segment */
+#if FFI_MMAP_EXEC_WRIT
+  /* The mmap magic is supposed to store the address of the executable
+     segment at the very end of the requested block.  */
+
+# define mmap_exec_offset(b,s) (*(ptrdiff_t*)((b)+(s)-sizeof(ptrdiff_t)))
+
+  /* We can only merge segments if their corresponding executable
+     segments are at identical offsets.  */
+# define check_segment_merge(S,b,s) \
+  (mmap_exec_offset((b),(s)) == (S)->exec_offset)
+
+# define add_segment_exec_offset(p,S) ((char*)(p) + (S)->exec_offset)
+# define sub_segment_exec_offset(p,S) ((char*)(p) - (S)->exec_offset)
+
+  /* The removal of sflags only works with HAVE_MORECORE == 0.  */
+
+# define get_segment_flags(S)   (IS_MMAPPED_BIT)
+# define set_segment_flags(S,v) \
+  (((v) != IS_MMAPPED_BIT) ? (ABORT, (v)) :                            \
+   (((S)->exec_offset =                                                        
\
+     mmap_exec_offset((S)->base, (S)->size)),                          \
+    (mmap_exec_offset((S)->base + (S)->exec_offset, (S)->size) !=      \
+     (S)->exec_offset) ? (ABORT, (v)) :                                        
\
+   (mmap_exec_offset((S)->base, (S)->size) = 0), (v)))
+
+  /* We use an offset here, instead of a pointer, because then, when
+     base changes, we don't have to modify this.  On architectures
+     with segmented addresses, this might not work.  */
+  ptrdiff_t    exec_offset;
+#else
+
+# define get_segment_flags(S)   ((S)->sflags)
+# define set_segment_flags(S,v) ((S)->sflags = (v))
+# define check_segment_merge(S,b,s) (1)
+
+  flag_t       sflags;           /* mmap and extern flag */
+#endif
+};
+
+#define is_mmapped_segment(S)  (get_segment_flags(S) & IS_MMAPPED_BIT)
+#define is_extern_segment(S)   (get_segment_flags(S) & EXTERN_BIT)
+
+typedef struct malloc_segment  msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+   A malloc_state holds all of the bookkeeping for a space.
+   The main fields are:
+
+  Top
+    The topmost chunk of the currently active segment. Its size is
+    cached in topsize.  The actual size of topmost space is
+    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+    fenceposts and segment records if necessary when getting more
+    space from the system.  The size at which to autotrim top is
+    cached from mparams in trim_check, except that it is disabled if
+    an autotrim fails.
+
+  Designated victim (dv)
+    This is the preferred chunk for servicing small requests that
+    don't have exact fits.  It is normally the chunk split off most
+    recently to service another small request.  Its size is cached in
+    dvsize. The link fields of this chunk are not maintained since it
+    is not kept in a bin.
+
+  SmallBins
+    An array of bin headers for free chunks.  These bins hold chunks
+    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+    chunks of all the same size, spaced 8 bytes apart.  To simplify
+    use in double-linked lists, each bin header acts as a malloc_chunk
+    pointing to the real first node, if it exists (else pointing to
+    itself).  This avoids special-casing for headers.  But to avoid
+    waste, we allocate only the fd/bk pointers of bins, and then use
+    repositioning tricks to treat these as the fields of a chunk.
+
+  TreeBins
+    Treebins are pointers to the roots of trees holding a range of
+    sizes. There are 2 equally spaced treebins for each power of two
+    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+    larger.
+
+  Bin maps
+    There is one bit map for small bins ("smallmap") and one for
+    treebins ("treemap).  Each bin sets its bit when non-empty, and
+    clears the bit when empty.  Bit operations are then used to avoid
+    bin-by-bin searching -- nearly all "search" is done without ever
+    looking at bins that won't be selected.  The bit maps
+    conservatively use 32 bits per map word, even if on 64bit system.
+    For a good description of some of the bit-based techniques used
+    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+    supplement at http://hackersdelight.org/). Many of these are
+    intended to reduce the branchiness of paths through malloc etc, as
+    well as to reduce the number of memory locations read or written.
+
+  Segments
+    A list of segments headed by an embedded malloc_segment record
+    representing the initial space.
+
+  Address check support
+    The least_addr field is the least address ever obtained from
+    MORECORE or MMAP. Attempted frees and reallocs of any address less
+    than this are trapped (unless INSECURE is defined).
+
+  Magic tag
+    A cross-check field that should always hold same value as mparams.magic.
+
+  Flags
+    Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+  Statistics
+    Each space keeps track of current and maximum system memory
+    obtained via MORECORE or MMAP.
+
+  Locking
+    If USE_LOCKS is defined, the "mutex" lock is acquired and released
+    around every public call using this mspace.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS        (32U)
+#define NTREEBINS         (32U)
+#define SMALLBIN_SHIFT    (3U)
+#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT     (8U)
+#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+  binmap_t   smallmap;
+  binmap_t   treemap;
+  size_t     dvsize;
+  size_t     topsize;
+  char*      least_addr;
+  mchunkptr  dv;
+  mchunkptr  top;
+  size_t     trim_check;
+  size_t     magic;
+  mchunkptr  smallbins[(NSMALLBINS+1)*2];
+  tbinptr    treebins[NTREEBINS];
+  size_t     footprint;
+  size_t     max_footprint;
+  flag_t     mflags;
+#if USE_LOCKS
+  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+  msegment   seg;
+};
+
+typedef struct malloc_state*    mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+  malloc_params holds global properties, including those that can be
+  dynamically set using mallopt. There is a single instance, mparams,
+  initialized in init_mparams.
+*/
+
+struct malloc_params {
+  size_t magic;
+  size_t page_size;
+  size_t granularity;
+  size_t mmap_threshold;
+  size_t trim_threshold;
+  flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* The global malloc_state used for all non-"mspace" calls */
+static struct malloc_state _gm_;
+#define gm                 (&_gm_)
+#define is_global(M)       ((M) == &_gm_)
+#define is_initialized(M)  ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
+#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
+#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)
+#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)
+#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)
+
+#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)
+#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+  ((M)->mflags | USE_LOCK_BIT) :\
+  ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+  (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))
+
+#define is_page_aligned(S)\
+   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/*  True if segment S holds address A */
+#define segment_holds(S, A)\
+  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= sp->base && addr < sp->base + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+      return 1;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+#ifndef MORECORE_CANNOT_TRIM
+#define should_trim(M,s)  ((s) > (M)->trim_check)
+#else  /* MORECORE_CANNOT_TRIM */
+#define should_trim(M,s)  (0)
+#endif /* MORECORE_CANNOT_TRIM */
+
+/*
+  TOP_FOOT_SIZE is padding at the end of a segment, including space
+  that may be needed to place segment records and fenceposts when new
+  noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+  (align_offset(chunk2mem(0))+pad_request(sizeof(struct 
malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* -------------------------------  Hooks -------------------------------- */
+
+/*
+  PREACTION should be defined to return 0 on success, and nonzero on
+  failure. If you are not using locking, you can redefine these to do
+  anything you like.
+*/
+
+#if USE_LOCKS
+
+/* Ensure locks are initialized */
+#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())
+
+#define PREACTION(M)  ((GLOBALLY_INITIALIZE() || use_lock(M))? 
ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif  /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif  /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+  USAGE_ERROR_ACTION is triggered on detected bad frees and
+  reallocs. The argument p is an address that might have triggered the
+  fault. It is ignored by the two predefined actions, but might be
+  useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)
+#define check_malloc_state(M)       do_check_malloc_state(M)
+
+static void   do_check_any_chunk(mstate m, mchunkptr p);
+static void   do_check_top_chunk(mstate m, mchunkptr p);
+static void   do_check_mmapped_chunk(mstate m, mchunkptr p);
+static void   do_check_inuse_chunk(mstate m, mchunkptr p);
+static void   do_check_free_chunk(mstate m, mchunkptr p);
+static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void   do_check_tree(mstate m, tchunkptr t);
+static void   do_check_treebin(mstate m, bindex_t i);
+static void   do_check_smallbin(mstate m, bindex_t i);
+static void   do_check_malloc_state(mstate m);
+static int    bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i)     (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I */
+#if defined(__GNUC__) && defined(i386)
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K;\
+    __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm"  (X));\
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int Y = (unsigned int)X;\
+    unsigned int N = ((Y - 0x100) >> 16) & 8;\
+    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+    N += K;\
+    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+    K = 14 - N + ((Y <<= K) >> 15);\
+    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+  }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+   ((i == NTREEBINS-1)? 0 : \
+    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
+   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i)              ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
+#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
+
+#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
+#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
+#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
+
+/* index corresponding to given bit */
+
+#if defined(__GNUC__) && defined(i386)
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\
+  I = (bindex_t)J;\
+}
+
+#else /* GNUC */
+#if  USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else /* USE_BUILTIN_FFS */
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int Y = X - 1;\
+  unsigned int K = Y >> (16-4) & 16;\
+  unsigned int N = K;        Y >>= K;\
+  N += K = Y >> (8-3) &  8;  Y >>= K;\
+  N += K = Y >> (4-2) &  4;  Y >>= K;\
+  N += K = Y >> (2-1) &  2;  Y >>= K;\
+  N += K = Y >> (1-0) &  1;  Y >>= K;\
+  I = (bindex_t)(N + Y);\
+}
+#endif /* USE_BUILTIN_FFS */
+#endif /* GNUC */
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x)         ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x)         ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+  For security, the main invariant is that malloc/free/etc never
+  writes to a static address other than malloc_state, unless static
+  malloc_state itself has been corrupted, which cannot occur via
+  malloc (because of these checks). In essence this means that we
+  believe all pointers, sizes, maps etc held in malloc_state, but
+  check all of those linked or offsetted from other embedded data
+  structures.  These checks are interspersed with main code in a way
+  that tends to minimize their run-time cost.
+
+  When FOOTERS is defined, in addition to range checking, we also
+  verify footer fields of inuse chunks, which can be used guarantee
+  that the mstate controlling malloc/free is intact.  This is a
+  streamlined version of the approach described by William Robertson
+  et al in "Run-time Detection of Heap-based Overflows" LISA'03
+  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+  of an inuse chunk holds the xor of its mstate and a random seed,
+  that is checked upon calls to free() and realloc().  This is
+  (probablistically) unguessable from outside the program, but can be
+  computed by any code successfully malloc'ing any chunk, so does not
+  itself provide protection against code that has already broken
+  security through some other means.  Unlike Robertson et al, we
+  always dynamically check addresses of all offset chunks (previous,
+  next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n)    ((char*)(p) < (char*)(n))
+/* Check if p has its cinuse bit on */
+#define ok_cinuse(p)     cinuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p)     pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n)    (1)
+#define ok_cinuse(p)     (1)
+#define ok_pinuse(p)     (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M)      ((M)->magic == mparams.magic)
+#else  /* (FOOTERS && !INSECURE) */
+#define ok_magic(M)      (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e)  __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e)  (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e)  (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+  ((mstate)(((mchunkptr)((char*)(p) +\
+    (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+  mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+  if (mparams.page_size == 0) {
+    size_t s;
+
+    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
+#if MORECORE_CONTIGUOUS
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
+#else  /* MORECORE_CONTIGUOUS */
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
+#endif /* MORECORE_CONTIGUOUS */
+
+#if (FOOTERS && !INSECURE)
+    {
+#if USE_DEV_RANDOM
+      int fd;
+      unsigned char buf[sizeof(size_t)];
+      /* Try to use /dev/urandom, else fall back on using time */
+      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+        s = *((size_t *) buf);
+        close(fd);
+      }
+      else
+#endif /* USE_DEV_RANDOM */
+        s = (size_t)(time(0) ^ (size_t)0x55555555U);
+
+      s |= (size_t)8U;    /* ensure nonzero */
+      s &= ~(size_t)7U;   /* improve chances of fault for bad values */
+
+    }
+#else /* (FOOTERS && !INSECURE) */
+    s = (size_t)0x58585858U;
+#endif /* (FOOTERS && !INSECURE) */
+    ACQUIRE_MAGIC_INIT_LOCK();
+    if (mparams.magic == 0) {
+      mparams.magic = s;
+      /* Set up lock for main malloc area */
+      INITIAL_LOCK(&gm->mutex);
+      gm->mflags = mparams.default_mflags;
+    }
+    RELEASE_MAGIC_INIT_LOCK();
+
+#ifndef WIN32
+    mparams.page_size = malloc_getpagesize;
+    mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
+                           DEFAULT_GRANULARITY : mparams.page_size);
+#else /* WIN32 */
+    {
+      SYSTEM_INFO system_info;
+      GetSystemInfo(&system_info);
+      mparams.page_size = system_info.dwPageSize;
+      mparams.granularity = system_info.dwAllocationGranularity;
+    }
+#endif /* WIN32 */
+
+    /* Sanity-check configuration:
+       size_t must be unsigned and as wide as pointer type.
+       ints must be at least 4 bytes.
+       alignment must be at least 8.
+       Alignment, min chunk size, and page size must all be powers of 2.
+    */
+    if ((sizeof(size_t) != sizeof(char*)) ||
+        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
+        (sizeof(int) < 4)  ||
+        (MALLOC_ALIGNMENT < (size_t)8U) ||
+        ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||
+        ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||
+        ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
+        ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))
+      ABORT;
+  }
+  return 0;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+  size_t val = (size_t)value;
+  init_mparams();
+  switch(param_number) {
+  case M_TRIM_THRESHOLD:
+    mparams.trim_threshold = val;
+    return 1;
+  case M_GRANULARITY:
+    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+      mparams.granularity = val;
+      return 1;
+    }
+    else
+      return 0;
+  case M_MMAP_THRESHOLD:
+    mparams.mmap_threshold = val;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc  */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+  msegmentptr sp = segment_holding(m, (char*)p);
+  size_t  sz = chunksize(p);
+  assert(sp != 0);
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(sz == m->topsize);
+  assert(sz > 0);
+  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+  assert(pinuse(p));
+  assert(!next_pinuse(p));
+}
+
+/* Check properties of (inuse) mmapped chunks */
+static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
+  size_t  sz = chunksize(p);
+  size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD);
+  assert(is_mmapped(p));
+  assert(use_mmap(m));
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(!is_small(sz));
+  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
+  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
+  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+  do_check_any_chunk(m, p);
+  assert(cinuse(p));
+  assert(next_pinuse(p));
+  /* If not pinuse and not mmapped, previous chunk has OK offset */
+  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
+  if (is_mmapped(p))
+    do_check_mmapped_chunk(m, p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+  size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+  mchunkptr next = chunk_plus_offset(p, sz);
+  do_check_any_chunk(m, p);
+  assert(!cinuse(p));
+  assert(!next_pinuse(p));
+  assert (!is_mmapped(p));
+  if (p != m->dv && p != m->top) {
+    if (sz >= MIN_CHUNK_SIZE) {
+      assert((sz & CHUNK_ALIGN_MASK) == 0);
+      assert(is_aligned(chunk2mem(p)));
+      assert(next->prev_foot == sz);
+      assert(pinuse(p));
+      assert (next == m->top || cinuse(next));
+      assert(p->fd->bk == p);
+      assert(p->bk->fd == p);
+    }
+    else  /* markers are always of size SIZE_T_SIZE */
+      assert(sz == SIZE_T_SIZE);
+  }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+    do_check_inuse_chunk(m, p);
+    assert((sz & CHUNK_ALIGN_MASK) == 0);
+    assert(sz >= MIN_CHUNK_SIZE);
+    assert(sz >= s);
+    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
+    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
+  }
+}
+
+/* Check a tree and its subtrees.  */
+static void do_check_tree(mstate m, tchunkptr t) {
+  tchunkptr head = 0;
+  tchunkptr u = t;
+  bindex_t tindex = t->index;
+  size_t tsize = chunksize(t);
+  bindex_t idx;
+  compute_tree_index(tsize, idx);
+  assert(tindex == idx);
+  assert(tsize >= MIN_LARGE_SIZE);
+  assert(tsize >= minsize_for_tree_index(idx));
+  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+  do { /* traverse through chain of same-sized nodes */
+    do_check_any_chunk(m, ((mchunkptr)u));
+    assert(u->index == tindex);
+    assert(chunksize(u) == tsize);
+    assert(!cinuse(u));
+    assert(!next_pinuse(u));
+    assert(u->fd->bk == u);
+    assert(u->bk->fd == u);
+    if (u->parent == 0) {
+      assert(u->child[0] == 0);
+      assert(u->child[1] == 0);
+    }
+    else {
+      assert(head == 0); /* only one node on chain has parent */
+      head = u;
+      assert(u->parent != u);
+      assert (u->parent->child[0] == u ||
+              u->parent->child[1] == u ||
+              *((tbinptr*)(u->parent)) == u);
+      if (u->child[0] != 0) {
+        assert(u->child[0]->parent == u);
+        assert(u->child[0] != u);
+        do_check_tree(m, u->child[0]);
+      }
+      if (u->child[1] != 0) {
+        assert(u->child[1]->parent == u);
+        assert(u->child[1] != u);
+        do_check_tree(m, u->child[1]);
+      }
+      if (u->child[0] != 0 && u->child[1] != 0) {
+        assert(chunksize(u->child[0]) < chunksize(u->child[1]));
+      }
+    }
+    u = u->fd;
+  } while (u != t);
+  assert(head != 0);
+}
+
+/*  Check all the chunks in a treebin.  */
+static void do_check_treebin(mstate m, bindex_t i) {
+  tbinptr* tb = treebin_at(m, i);
+  tchunkptr t = *tb;
+  int empty = (m->treemap & (1U << i)) == 0;
+  if (t == 0)
+    assert(empty);
+  if (!empty)
+    do_check_tree(m, t);
+}
+
+/*  Check all the chunks in a smallbin.  */
+static void do_check_smallbin(mstate m, bindex_t i) {
+  sbinptr b = smallbin_at(m, i);
+  mchunkptr p = b->bk;
+  unsigned int empty = (m->smallmap & (1U << i)) == 0;
+  if (p == b)
+    assert(empty);
+  if (!empty) {
+    for (; p != b; p = p->bk) {
+      size_t size = chunksize(p);
+      mchunkptr q;
+      /* each chunk claims to be free */
+      do_check_free_chunk(m, p);
+      /* chunk belongs in bin */
+      assert(small_index(size) == i);
+      assert(p->bk == b || chunksize(p->bk) == chunksize(p));
+      /* chunk is followed by an inuse chunk */
+      q = next_chunk(p);
+      if (q->head != FENCEPOST_HEAD)
+        do_check_inuse_chunk(m, q);
+    }
+  }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+  size_t size = chunksize(x);
+  if (is_small(size)) {
+    bindex_t sidx = small_index(size);
+    sbinptr b = smallbin_at(m, sidx);
+    if (smallmap_is_marked(m, sidx)) {
+      mchunkptr p = b;
+      do {
+        if (p == x)
+          return 1;
+      } while ((p = p->fd) != b);
+    }
+  }
+  else {
+    bindex_t tidx;
+    compute_tree_index(size, tidx);
+    if (treemap_is_marked(m, tidx)) {
+      tchunkptr t = *treebin_at(m, tidx);
+      size_t sizebits = size << leftshift_for_tree_index(tidx);
+      while (t != 0 && chunksize(t) != size) {
+        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+        sizebits <<= 1;
+      }
+      if (t != 0) {
+        tchunkptr u = t;
+        do {
+          if (u == (tchunkptr)x)
+            return 1;
+        } while ((u = u->fd) != t);
+      }
+    }
+  }
+  return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+  size_t sum = 0;
+  if (is_initialized(m)) {
+    msegmentptr s = &m->seg;
+    sum += m->topsize + TOP_FOOT_SIZE;
+    while (s != 0) {
+      mchunkptr q = align_as_chunk(s->base);
+      mchunkptr lastq = 0;
+      assert(pinuse(q));
+      while (segment_holds(s, q) &&
+             q != m->top && q->head != FENCEPOST_HEAD) {
+        sum += chunksize(q);
+        if (cinuse(q)) {
+          assert(!bin_find(m, q));
+          do_check_inuse_chunk(m, q);
+        }
+        else {
+          assert(q == m->dv || bin_find(m, q));
+          assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
+          do_check_free_chunk(m, q);
+        }
+        lastq = q;
+        q = next_chunk(q);
+      }
+      s = s->next;
+    }
+  }
+  return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+  bindex_t i;
+  size_t total;
+  /* check bins */
+  for (i = 0; i < NSMALLBINS; ++i)
+    do_check_smallbin(m, i);
+  for (i = 0; i < NTREEBINS; ++i)
+    do_check_treebin(m, i);
+
+  if (m->dvsize != 0) { /* check dv chunk */
+    do_check_any_chunk(m, m->dv);
+    assert(m->dvsize == chunksize(m->dv));
+    assert(m->dvsize >= MIN_CHUNK_SIZE);
+    assert(bin_find(m, m->dv) == 0);
+  }
+
+  if (m->top != 0) {   /* check top chunk */
+    do_check_top_chunk(m, m->top);
+    assert(m->topsize == chunksize(m->top));
+    assert(m->topsize > 0);
+    assert(bin_find(m, m->top) == 0);
+  }
+
+  total = traverse_and_check(m);
+  assert(total <= m->footprint);
+  assert(m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  if (!PREACTION(m)) {
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      size_t nfree = SIZE_T_ONE; /* top always free */
+      size_t mfree = m->topsize + TOP_FOOT_SIZE;
+      size_t sum = mfree;
+      msegmentptr s = &m->seg;
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          size_t sz = chunksize(q);
+          sum += sz;
+          if (!cinuse(q)) {
+            mfree += sz;
+            ++nfree;
+          }
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+
+      nm.arena    = sum;
+      nm.ordblks  = nfree;
+      nm.hblkhd   = m->footprint - sum;
+      nm.usmblks  = m->max_footprint;
+      nm.uordblks = m->footprint - mfree;
+      nm.fordblks = mfree;
+      nm.keepcost = m->topsize;
+    }
+
+    POSTACTION(m);
+  }
+  return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+  if (!PREACTION(m)) {
+    size_t maxfp = 0;
+    size_t fp = 0;
+    size_t used = 0;
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      msegmentptr s = &m->seg;
+      maxfp = m->max_footprint;
+      fp = m->footprint;
+      used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          if (!cinuse(q))
+            used -= chunksize(q);
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+    }
+
+    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
+    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));
+    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));
+
+    POSTACTION(m);
+  }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+  Various forms of linking and unlinking are defined as macros.  Even
+  the ones for trees, which are very long but have very short typical
+  paths.  This is ugly but reduces reliance on inlining support of
+  compilers.
+*/
+
+/* Link a free chunk into a smallbin  */
+#define insert_small_chunk(M, P, S) {\
+  bindex_t I  = small_index(S);\
+  mchunkptr B = smallbin_at(M, I);\
+  mchunkptr F = B;\
+  assert(S >= MIN_CHUNK_SIZE);\
+  if (!smallmap_is_marked(M, I))\
+    mark_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, B->fd)))\
+    F = B->fd;\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+  B->fd = P;\
+  F->bk = P;\
+  P->fd = F;\
+  P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin  */
+#define unlink_small_chunk(M, P, S) {\
+  mchunkptr F = P->fd;\
+  mchunkptr B = P->bk;\
+  bindex_t I = small_index(S);\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (F == B)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+                   (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+    F->bk = B;\
+    B->fd = F;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+  mchunkptr F = P->fd;\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (B == F)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, F))) {\
+    B->fd = F;\
+    F->bk = B;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+  size_t DVS = M->dvsize;\
+  if (DVS != 0) {\
+    mchunkptr DV = M->dv;\
+    assert(is_small(DVS));\
+    insert_small_chunk(M, DV, DVS);\
+  }\
+  M->dvsize = S;\
+  M->dv = P;\
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+  tbinptr* H;\
+  bindex_t I;\
+  compute_tree_index(S, I);\
+  H = treebin_at(M, I);\
+  X->index = I;\
+  X->child[0] = X->child[1] = 0;\
+  if (!treemap_is_marked(M, I)) {\
+    mark_treemap(M, I);\
+    *H = X;\
+    X->parent = (tchunkptr)H;\
+    X->fd = X->bk = X;\
+  }\
+  else {\
+    tchunkptr T = *H;\
+    size_t K = S << leftshift_for_tree_index(I);\
+    for (;;) {\
+      if (chunksize(T) != S) {\
+        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+        K <<= 1;\
+        if (*C != 0)\
+          T = *C;\
+        else if (RTCHECK(ok_address(M, C))) {\
+          *C = X;\
+          X->parent = T;\
+          X->fd = X->bk = X;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+      else {\
+        tchunkptr F = T->fd;\
+        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+          T->fd = F->bk = X;\
+          X->fd = F;\
+          X->bk = T;\
+          X->parent = 0;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+    }\
+  }\
+}
+
+/*
+  Unlink steps:
+
+  1. If x is a chained node, unlink it from its same-sized fd/bk links
+     and choose its bk node as its replacement.
+  2. If x was the last node of its size, but not a leaf node, it must
+     be replaced with a leaf node (not merely one with an open left or
+     right), to make sure that lefts and rights of descendents
+     correspond properly to bit masks.  We use the rightmost descendent
+     of x.  We could use any other leaf, but this is easy to locate and
+     tends to counteract removal of leftmosts elsewhere, and so keeps
+     paths shorter than minimally guaranteed.  This doesn't loop much
+     because on average a node in a tree is near the bottom.
+  3. If x is the base of a chain (i.e., has parent links) relink
+     x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+  tchunkptr XP = X->parent;\
+  tchunkptr R;\
+  if (X->bk != X) {\
+    tchunkptr F = X->fd;\
+    R = X->bk;\
+    if (RTCHECK(ok_address(M, F))) {\
+      F->bk = R;\
+      R->fd = F;\
+    }\
+    else {\
+      CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+  else {\
+    tchunkptr* RP;\
+    if (((R = *(RP = &(X->child[1]))) != 0) ||\
+        ((R = *(RP = &(X->child[0]))) != 0)) {\
+      tchunkptr* CP;\
+      while ((*(CP = &(R->child[1])) != 0) ||\
+             (*(CP = &(R->child[0])) != 0)) {\
+        R = *(RP = CP);\
+      }\
+      if (RTCHECK(ok_address(M, RP)))\
+        *RP = 0;\
+      else {\
+        CORRUPTION_ERROR_ACTION(M);\
+      }\
+    }\
+  }\
+  if (XP != 0) {\
+    tbinptr* H = treebin_at(M, X->index);\
+    if (X == *H) {\
+      if ((*H = R) == 0) \
+        clear_treemap(M, X->index);\
+    }\
+    else if (RTCHECK(ok_address(M, XP))) {\
+      if (XP->child[0] == X) \
+        XP->child[0] = R;\
+      else \
+        XP->child[1] = R;\
+    }\
+    else\
+      CORRUPTION_ERROR_ACTION(M);\
+    if (R != 0) {\
+      if (RTCHECK(ok_address(M, R))) {\
+        tchunkptr C0, C1;\
+        R->parent = XP;\
+        if ((C0 = X->child[0]) != 0) {\
+          if (RTCHECK(ok_address(M, C0))) {\
+            R->child[0] = C0;\
+            C0->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+        if ((C1 = X->child[1]) != 0) {\
+          if (RTCHECK(ok_address(M, C1))) {\
+            R->child[1] = C1;\
+            C1->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+      }\
+      else\
+        CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+  if (is_small(S)) insert_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+  if (is_small(S)) unlink_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#if ONLY_MSPACES
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+#else /* ONLY_MSPACES */
+#if MSPACES
+#define internal_malloc(m, b)\
+   (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
+#define internal_free(m, mem)\
+   if (m == gm) dlfree(mem); else mspace_free(m,mem);
+#else /* MSPACES */
+#define internal_malloc(m, b) dlmalloc(b)
+#define internal_free(m, mem) dlfree(mem)
+#endif /* MSPACES */
+#endif /* ONLY_MSPACES */
+
+/* -----------------------  Direct-mmapping chunks ----------------------- */
+
+/*
+  Directly mmapped chunks are set up with an offset to the start of
+  the mmapped region stored in the prev_foot field of the chunk. This
+  allows reconstruction of the required argument to MUNMAP when freed,
+  and also allows adjustment of the returned chunk to meet alignment
+  requirements (especially in memalign).  There is also enough space
+  allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain
+  the PINUSE bit so frees can be checked.
+*/
+
+/* Malloc using mmap */
+static void* mmap_alloc(mstate m, size_t nb) {
+  size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  if (mmsize > nb) {     /* Check for wrap around 0 */
+    char* mm = (char*)(DIRECT_MMAP(mmsize));
+    if (mm != CMFAIL) {
+      size_t offset = align_offset(chunk2mem(mm));
+      size_t psize = mmsize - offset - MMAP_FOOT_PAD;
+      mchunkptr p = (mchunkptr)(mm + offset);
+      p->prev_foot = offset | IS_MMAPPED_BIT;
+      (p)->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, p, psize);
+      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
+
+      if (mm < m->least_addr)
+        m->least_addr = mm;
+      if ((m->footprint += mmsize) > m->max_footprint)
+        m->max_footprint = m->footprint;
+      assert(is_aligned(chunk2mem(p)));
+      check_mmapped_chunk(m, p);
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* Realloc using mmap */
+static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
+  size_t oldsize = chunksize(oldp);
+  if (is_small(nb)) /* Can't shrink mmap regions below small size */
+    return 0;
+  /* Keep old chunk if big enough but not too big */
+  if (oldsize >= nb + SIZE_T_SIZE &&
+      (oldsize - nb) <= (mparams.granularity << 1))
+    return oldp;
+  else {
+    size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
+    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
+    size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +
+                                         CHUNK_ALIGN_MASK);
+    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
+                                  oldmmsize, newmmsize, 1);
+    if (cp != CMFAIL) {
+      mchunkptr newp = (mchunkptr)(cp + offset);
+      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
+      newp->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, newp, psize);
+      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
+
+      if (cp < m->least_addr)
+        m->least_addr = cp;
+      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
+        m->max_footprint = m->footprint;
+      check_mmapped_chunk(m, newp);
+      return newp;
+    }
+  }
+  return 0;
+}
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+  /* Ensure alignment */
+  size_t offset = align_offset(chunk2mem(p));
+  p = (mchunkptr)((char*)p + offset);
+  psize -= offset;
+
+  m->top = p;
+  m->topsize = psize;
+  p->head = psize | PINUSE_BIT;
+  /* set size of fake trailing chunk holding overhead space only once */
+  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+  m->trim_check = mparams.trim_threshold; /* reset on each update */
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+  /* Establish circular links for smallbins */
+  bindex_t i;
+  for (i = 0; i < NSMALLBINS; ++i) {
+    sbinptr bin = smallbin_at(m,i);
+    bin->fd = bin->bk = bin;
+  }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+  int i;
+  ++malloc_corruption_error_count;
+  /* Reinitialize fields to forget about all memory */
+  m->smallbins = m->treebins = 0;
+  m->dvsize = m->topsize = 0;
+  m->seg.base = 0;
+  m->seg.size = 0;
+  m->seg.next = 0;
+  m->top = m->dv = 0;
+  for (i = 0; i < NTREEBINS; ++i)
+    *treebin_at(m, i) = 0;
+  init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+                           size_t nb) {
+  mchunkptr p = align_as_chunk(newbase);
+  mchunkptr oldfirst = align_as_chunk(oldbase);
+  size_t psize = (char*)oldfirst - (char*)p;
+  mchunkptr q = chunk_plus_offset(p, nb);
+  size_t qsize = psize - nb;
+  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+  assert((char*)oldfirst > (char*)q);
+  assert(pinuse(oldfirst));
+  assert(qsize >= MIN_CHUNK_SIZE);
+
+  /* consolidate remainder with first chunk of old base */
+  if (oldfirst == m->top) {
+    size_t tsize = m->topsize += qsize;
+    m->top = q;
+    q->head = tsize | PINUSE_BIT;
+    check_top_chunk(m, q);
+  }
+  else if (oldfirst == m->dv) {
+    size_t dsize = m->dvsize += qsize;
+    m->dv = q;
+    set_size_and_pinuse_of_free_chunk(q, dsize);
+  }
+  else {
+    if (!cinuse(oldfirst)) {
+      size_t nsize = chunksize(oldfirst);
+      unlink_chunk(m, oldfirst, nsize);
+      oldfirst = chunk_plus_offset(oldfirst, nsize);
+      qsize += nsize;
+    }
+    set_free_with_pinuse(q, qsize, oldfirst);
+    insert_chunk(m, q, qsize);
+    check_free_chunk(m, q);
+  }
+
+  check_malloced_chunk(m, chunk2mem(p), nb);
+  return chunk2mem(p);
+}
+
+
+/* Add a segment to hold a new noncontiguous region */
+static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
+  /* Determine locations and sizes of segment, fenceposts, old top */
+  char* old_top = (char*)m->top;
+  msegmentptr oldsp = segment_holding(m, old_top);
+  char* old_end = oldsp->base + oldsp->size;
+  size_t ssize = pad_request(sizeof(struct malloc_segment));
+  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  size_t offset = align_offset(chunk2mem(rawsp));
+  char* asp = rawsp + offset;
+  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
+  mchunkptr sp = (mchunkptr)csp;
+  msegmentptr ss = (msegmentptr)(chunk2mem(sp));
+  mchunkptr tnext = chunk_plus_offset(sp, ssize);
+  mchunkptr p = tnext;
+  int nfences = 0;
+
+  /* reset top to new space */
+  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+
+  /* Set up segment record */
+  assert(is_aligned(ss));
+  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
+  *ss = m->seg; /* Push current record */
+  m->seg.base = tbase;
+  m->seg.size = tsize;
+  set_segment_flags(&m->seg, mmapped);
+  m->seg.next = ss;
+
+  /* Insert trailing fenceposts */
+  for (;;) {
+    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
+    p->head = FENCEPOST_HEAD;
+    ++nfences;
+    if ((char*)(&(nextp->head)) < old_end)
+      p = nextp;
+    else
+      break;
+  }
+  assert(nfences >= 2);
+
+  /* Insert the rest of old top into a bin as an ordinary free chunk */
+  if (csp != old_top) {
+    mchunkptr q = (mchunkptr)old_top;
+    size_t psize = csp - old_top;
+    mchunkptr tn = chunk_plus_offset(q, psize);
+    set_free_with_pinuse(q, psize, tn);
+    insert_chunk(m, q, psize);
+  }
+
+  check_top_chunk(m, m->top);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+  char* tbase = CMFAIL;
+  size_t tsize = 0;
+  flag_t mmap_flag = 0;
+
+  init_mparams();
+
+  /* Directly map large chunks */
+  if (use_mmap(m) && nb >= mparams.mmap_threshold) {
+    void* mem = mmap_alloc(m, nb);
+    if (mem != 0)
+      return mem;
+  }
+
+  /*
+    Try getting memory in any of three ways (in most-preferred to
+    least-preferred order):
+    1. A call to MORECORE that can normally contiguously extend memory.
+       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
+       or main space is mmapped or a previous contiguous call failed)
+    2. A call to MMAP new space (disabled if not HAVE_MMAP).
+       Note that under the default settings, if MORECORE is unable to
+       fulfill a request, and HAVE_MMAP is true, then mmap is
+       used as a noncontiguous system allocator. This is a useful backup
+       strategy for systems with holes in address spaces -- in this case
+       sbrk cannot contiguously expand the heap, but mmap may be able to
+       find space.
+    3. A call to MORECORE that cannot usually contiguously extend memory.
+       (disabled if not HAVE_MORECORE)
+  */
+
+  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
+    char* br = CMFAIL;
+    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
+    size_t asize = 0;
+    ACQUIRE_MORECORE_LOCK();
+
+    if (ss == 0) {  /* First time through or recovery */
+      char* base = (char*)CALL_MORECORE(0);
+      if (base != CMFAIL) {
+        asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
+        /* Adjust to end on a page boundary */
+        if (!is_page_aligned(base))
+          asize += (page_align((size_t)base) - (size_t)base);
+        /* Can't call MORECORE if size is negative when treated as signed */
+        if (asize < HALF_MAX_SIZE_T &&
+            (br = (char*)(CALL_MORECORE(asize))) == base) {
+          tbase = base;
+          tsize = asize;
+        }
+      }
+    }
+    else {
+      /* Subtract out existing available top space from MORECORE request. */
+      asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE);
+      /* Use mem here only if it did continuously extend old space */
+      if (asize < HALF_MAX_SIZE_T &&
+          (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
+        tbase = br;
+        tsize = asize;
+      }
+    }
+
+    if (tbase == CMFAIL) {    /* Cope with partial failure */
+      if (br != CMFAIL) {    /* Try to use/extend the space we did get */
+        if (asize < HALF_MAX_SIZE_T &&
+            asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {
+          size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - 
asize);
+          if (esize < HALF_MAX_SIZE_T) {
+            char* end = (char*)CALL_MORECORE(esize);
+            if (end != CMFAIL)
+              asize += esize;
+            else {            /* Can't use; try to release */
+              (void)CALL_MORECORE(-asize);
+              br = CMFAIL;
+            }
+          }
+        }
+      }
+      if (br != CMFAIL) {    /* Use the space we did get */
+        tbase = br;
+        tsize = asize;
+      }
+      else
+        disable_contiguous(m); /* Don't try contiguous path in the future */
+    }
+
+    RELEASE_MORECORE_LOCK();
+  }
+
+  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
+    size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
+    size_t rsize = granularity_align(req);
+    if (rsize > nb) { /* Fail if wraps around zero */
+      char* mp = (char*)(CALL_MMAP(rsize));
+      if (mp != CMFAIL) {
+        tbase = mp;
+        tsize = rsize;
+        mmap_flag = IS_MMAPPED_BIT;
+      }
+    }
+  }
+
+  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
+    size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
+    if (asize < HALF_MAX_SIZE_T) {
+      char* br = CMFAIL;
+      char* end = CMFAIL;
+      ACQUIRE_MORECORE_LOCK();
+      br = (char*)(CALL_MORECORE(asize));
+      end = (char*)(CALL_MORECORE(0));
+      RELEASE_MORECORE_LOCK();
+      if (br != CMFAIL && end != CMFAIL && br < end) {
+        size_t ssize = end - br;
+        if (ssize > nb + TOP_FOOT_SIZE) {
+          tbase = br;
+          tsize = ssize;
+        }
+      }
+    }
+  }
+
+  if (tbase != CMFAIL) {
+
+    if ((m->footprint += tsize) > m->max_footprint)
+      m->max_footprint = m->footprint;
+
+    if (!is_initialized(m)) { /* first-time initialization */
+      m->seg.base = m->least_addr = tbase;
+      m->seg.size = tsize;
+      set_segment_flags(&m->seg, mmap_flag);
+      m->magic = mparams.magic;
+      init_bins(m);
+      if (is_global(m)) 
+        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+      else {
+        /* Offset top by embedded malloc_state */
+        mchunkptr mn = next_chunk(mem2chunk(m));
+        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
+      }
+    }
+
+    else {
+      /* Try to merge with an existing segment */
+      msegmentptr sp = &m->seg;
+      while (sp != 0 && tbase != sp->base + sp->size)
+        sp = sp->next;
+      if (sp != 0 &&
+          !is_extern_segment(sp) &&
+         check_segment_merge(sp, tbase, tsize) &&
+          (get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag &&
+          segment_holds(sp, m->top)) { /* append */
+        sp->size += tsize;
+        init_top(m, m->top, m->topsize + tsize);
+      }
+      else {
+        if (tbase < m->least_addr)
+          m->least_addr = tbase;
+        sp = &m->seg;
+        while (sp != 0 && sp->base != tbase + tsize)
+          sp = sp->next;
+        if (sp != 0 &&
+            !is_extern_segment(sp) &&
+           check_segment_merge(sp, tbase, tsize) &&
+            (get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag) {
+          char* oldbase = sp->base;
+          sp->base = tbase;
+          sp->size += tsize;
+          return prepend_alloc(m, tbase, oldbase, nb);
+        }
+        else
+          add_segment(m, tbase, tsize, mmap_flag);
+      }
+    }
+
+    if (nb < m->topsize) { /* Allocate from new or extended top space */
+      size_t rsize = m->topsize -= nb;
+      mchunkptr p = m->top;
+      mchunkptr r = m->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+      check_top_chunk(m, m->top);
+      check_malloced_chunk(m, chunk2mem(p), nb);
+      return chunk2mem(p);
+    }
+  }
+
+  MALLOC_FAILURE_ACTION;
+  return 0;
+}
+
+/* -----------------------  system deallocation -------------------------- */
+
+/* Unmap and unlink any mmapped segments that don't contain used chunks */
+static size_t release_unused_segments(mstate m) {
+  size_t released = 0;
+  msegmentptr pred = &m->seg;
+  msegmentptr sp = pred->next;
+  while (sp != 0) {
+    char* base = sp->base;
+    size_t size = sp->size;
+    msegmentptr next = sp->next;
+    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
+      mchunkptr p = align_as_chunk(base);
+      size_t psize = chunksize(p);
+      /* Can unmap if first chunk holds entire segment and not pinned */
+      if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
+        tchunkptr tp = (tchunkptr)p;
+        assert(segment_holds(sp, (char*)sp));
+        if (p == m->dv) {
+          m->dv = 0;
+          m->dvsize = 0;
+        }
+        else {
+          unlink_large_chunk(m, tp);
+        }
+        if (CALL_MUNMAP(base, size) == 0) {
+          released += size;
+          m->footprint -= size;
+          /* unlink obsoleted record */
+          sp = pred;
+          sp->next = next;
+        }
+        else { /* back out if cannot unmap */
+          insert_large_chunk(m, tp, psize);
+        }
+      }
+    }
+    pred = sp;
+    sp = next;
+  }
+  return released;
+}
+
+static int sys_trim(mstate m, size_t pad) {
+  size_t released = 0;
+  if (pad < MAX_REQUEST && is_initialized(m)) {
+    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+
+    if (m->topsize > pad) {
+      /* Shrink top space in granularity-size units, keeping at least one */
+      size_t unit = mparams.granularity;
+      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
+                      SIZE_T_ONE) * unit;
+      msegmentptr sp = segment_holding(m, (char*)m->top);
+
+      if (!is_extern_segment(sp)) {
+        if (is_mmapped_segment(sp)) {
+          if (HAVE_MMAP &&
+              sp->size >= extra &&
+              !has_segment_link(m, sp)) { /* can't shrink if pinned */
+            size_t newsize = sp->size - extra;
+            /* Prefer mremap, fall back to munmap */
+            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+              released = extra;
+            }
+          }
+        }
+        else if (HAVE_MORECORE) {
+          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
+          ACQUIRE_MORECORE_LOCK();
+          {
+            /* Make sure end of memory is where we last set it. */
+            char* old_br = (char*)(CALL_MORECORE(0));
+            if (old_br == sp->base + sp->size) {
+              char* rel_br = (char*)(CALL_MORECORE(-extra));
+              char* new_br = (char*)(CALL_MORECORE(0));
+              if (rel_br != CMFAIL && new_br < old_br)
+                released = old_br - new_br;
+            }
+          }
+          RELEASE_MORECORE_LOCK();
+        }
+      }
+
+      if (released != 0) {
+        sp->size -= released;
+        m->footprint -= released;
+        init_top(m, m->top, m->topsize - released);
+        check_top_chunk(m, m->top);
+      }
+    }
+
+    /* Unmap any unused mmapped segments */
+    if (HAVE_MMAP) 
+      released += release_unused_segments(m);
+
+    /* On failure, disable autotrim to avoid repeated failed future calls */
+    if (released == 0)
+      m->trim_check = MAX_SIZE_T;
+  }
+
+  return (released != 0)? 1 : 0;
+}
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+  tchunkptr v = 0;
+  size_t rsize = -nb; /* Unsigned negation */
+  tchunkptr t;
+  bindex_t idx;
+  compute_tree_index(nb, idx);
+
+  if ((t = *treebin_at(m, idx)) != 0) {
+    /* Traverse tree for this bin looking for node with size == nb */
+    size_t sizebits = nb << leftshift_for_tree_index(idx);
+    tchunkptr rst = 0;  /* The deepest untaken right subtree */
+    for (;;) {
+      tchunkptr rt;
+      size_t trem = chunksize(t) - nb;
+      if (trem < rsize) {
+        v = t;
+        if ((rsize = trem) == 0)
+          break;
+      }
+      rt = t->child[1];
+      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+      if (rt != 0 && rt != t)
+        rst = rt;
+      if (t == 0) {
+        t = rst; /* set t to least subtree holding sizes > nb */
+        break;
+      }
+      sizebits <<= 1;
+    }
+  }
+
+  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+    if (leftbits != 0) {
+      bindex_t i;
+      binmap_t leastbit = least_bit(leftbits);
+      compute_bit2idx(leastbit, i);
+      t = *treebin_at(m, i);
+    }
+  }
+
+  while (t != 0) { /* find smallest of tree or subtree */
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+    t = leftmost_child(t);
+  }
+
+  /*  If dv is a better fit, return 0 so malloc will use it */
+  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+    if (RTCHECK(ok_address(m, v))) { /* split */
+      mchunkptr r = chunk_plus_offset(v, nb);
+      assert(chunksize(v) == rsize + nb);
+      if (RTCHECK(ok_next(v, r))) {
+        unlink_large_chunk(m, v);
+        if (rsize < MIN_CHUNK_SIZE)
+          set_inuse_and_pinuse(m, v, (rsize + nb));
+        else {
+          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+          set_size_and_pinuse_of_free_chunk(r, rsize);
+          insert_chunk(m, r, rsize);
+        }
+        return chunk2mem(v);
+      }
+    }
+    CORRUPTION_ERROR_ACTION(m);
+  }
+  return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+  tchunkptr t, v;
+  size_t rsize;
+  bindex_t i;
+  binmap_t leastbit = least_bit(m->treemap);
+  compute_bit2idx(leastbit, i);
+
+  v = t = *treebin_at(m, i);
+  rsize = chunksize(t) - nb;
+
+  while ((t = leftmost_child(t)) != 0) {
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+  }
+
+  if (RTCHECK(ok_address(m, v))) {
+    mchunkptr r = chunk_plus_offset(v, nb);
+    assert(chunksize(v) == rsize + nb);
+    if (RTCHECK(ok_next(v, r))) {
+      unlink_large_chunk(m, v);
+      if (rsize < MIN_CHUNK_SIZE)
+        set_inuse_and_pinuse(m, v, (rsize + nb));
+      else {
+        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        replace_dv(m, r, rsize);
+      }
+      return chunk2mem(v);
+    }
+  }
+
+  CORRUPTION_ERROR_ACTION(m);
+  return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+  if (bytes >= MAX_REQUEST) {
+    MALLOC_FAILURE_ACTION;
+    return 0;
+  }
+  if (!PREACTION(m)) {
+    mchunkptr oldp = mem2chunk(oldmem);
+    size_t oldsize = chunksize(oldp);
+    mchunkptr next = chunk_plus_offset(oldp, oldsize);
+    mchunkptr newp = 0;
+    void* extra = 0;
+
+    /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
+                ok_next(oldp, next) && ok_pinuse(next))) {
+      size_t nb = request2size(bytes);
+      if (is_mmapped(oldp))
+        newp = mmap_resize(m, oldp, nb);
+      else if (oldsize >= nb) { /* already big enough */
+        size_t rsize = oldsize - nb;
+        newp = oldp;
+        if (rsize >= MIN_CHUNK_SIZE) {
+          mchunkptr remainder = chunk_plus_offset(newp, nb);
+          set_inuse(m, newp, nb);
+          set_inuse(m, remainder, rsize);
+          extra = chunk2mem(remainder);
+        }
+      }
+      else if (next == m->top && oldsize + m->topsize > nb) {
+        /* Expand into top */
+        size_t newsize = oldsize + m->topsize;
+        size_t newtopsize = newsize - nb;
+        mchunkptr newtop = chunk_plus_offset(oldp, nb);
+        set_inuse(m, oldp, nb);
+        newtop->head = newtopsize |PINUSE_BIT;
+        m->top = newtop;
+        m->topsize = newtopsize;
+        newp = oldp;
+      }
+    }
+    else {
+      USAGE_ERROR_ACTION(m, oldmem);
+      POSTACTION(m);
+      return 0;
+    }
+
+    POSTACTION(m);
+
+    if (newp != 0) {
+      if (extra != 0) {
+        internal_free(m, extra);
+      }
+      check_inuse_chunk(m, newp);
+      return chunk2mem(newp);
+    }
+    else {
+      void* newmem = internal_malloc(m, bytes);
+      if (newmem != 0) {
+        size_t oc = oldsize - overhead_for(oldp);
+        memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+        internal_free(m, oldmem);
+      }
+      return newmem;
+    }
+  }
+  return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */
+    return internal_malloc(m, bytes);
+  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+    alignment = MIN_CHUNK_SIZE;
+  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+    size_t a = MALLOC_ALIGNMENT << 1;
+    while (a < alignment) a <<= 1;
+    alignment = a;
+  }
+  
+  if (bytes >= MAX_REQUEST - alignment) {
+    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
+      MALLOC_FAILURE_ACTION;
+    }
+  }
+  else {
+    size_t nb = request2size(bytes);
+    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+    char* mem = (char*)internal_malloc(m, req);
+    if (mem != 0) {
+      void* leader = 0;
+      void* trailer = 0;
+      mchunkptr p = mem2chunk(mem);
+
+      if (PREACTION(m)) return 0;
+      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+        /*
+          Find an aligned spot inside chunk.  Since we need to give
+          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+          the first calculation places us at a spot with less than
+          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+          We've allocated enough total room so that this is always
+          possible.
+        */
+        char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+                                                       alignment -
+                                                       SIZE_T_ONE)) &
+                                             -alignment));
+        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+          br : br+alignment;
+        mchunkptr newp = (mchunkptr)pos;
+        size_t leadsize = pos - (char*)(p);
+        size_t newsize = chunksize(p) - leadsize;
+
+        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
+          newp->prev_foot = p->prev_foot + leadsize;
+          newp->head = (newsize|CINUSE_BIT);
+        }
+        else { /* Otherwise, give back leader, use the rest */
+          set_inuse(m, newp, newsize);
+          set_inuse(m, p, leadsize);
+          leader = chunk2mem(p);
+        }
+        p = newp;
+      }
+
+      /* Give back spare room at the end */
+      if (!is_mmapped(p)) {
+        size_t size = chunksize(p);
+        if (size > nb + MIN_CHUNK_SIZE) {
+          size_t remainder_size = size - nb;
+          mchunkptr remainder = chunk_plus_offset(p, nb);
+          set_inuse(m, p, nb);
+          set_inuse(m, remainder, remainder_size);
+          trailer = chunk2mem(remainder);
+        }
+      }
+
+      assert (chunksize(p) >= nb);
+      assert((((size_t)(chunk2mem(p))) % alignment) == 0);
+      check_inuse_chunk(m, p);
+      POSTACTION(m);
+      if (leader != 0) {
+        internal_free(m, leader);
+      }
+      if (trailer != 0) {
+        internal_free(m, trailer);
+      }
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* ------------------------ comalloc/coalloc support --------------------- */
+
+static void** ialloc(mstate m,
+                     size_t n_elements,
+                     size_t* sizes,
+                     int opts,
+                     void* chunks[]) {
+  /*
+    This provides common support for independent_X routines, handling
+    all of the combinations that can result.
+
+    The opts arg has:
+    bit 0 set if all elements are same size (using sizes[0])
+    bit 1 set if elements should be zeroed
+  */
+
+  size_t    element_size;   /* chunksize of each element, if all same */
+  size_t    contents_size;  /* total size of elements */
+  size_t    array_size;     /* request size of pointer array */
+  void*     mem;            /* malloced aggregate space */
+  mchunkptr p;              /* corresponding chunk */
+  size_t    remainder_size; /* remaining bytes while splitting */
+  void**    marray;         /* either "chunks" or malloced ptr array */
+  mchunkptr array_chunk;    /* chunk for malloced ptr array */
+  flag_t    was_enabled;    /* to disable mmap */
+  size_t    size;
+  size_t    i;
+
+  /* compute array length, if needed */
+  if (chunks != 0) {
+    if (n_elements == 0)
+      return chunks; /* nothing to do */
+    marray = chunks;
+    array_size = 0;
+  }
+  else {
+    /* if empty req, must still return chunk representing empty array */
+    if (n_elements == 0)
+      return (void**)internal_malloc(m, 0);
+    marray = 0;
+    array_size = request2size(n_elements * (sizeof(void*)));
+  }
+
+  /* compute total element size */
+  if (opts & 0x1) { /* all-same-size */
+    element_size = request2size(*sizes);
+    contents_size = n_elements * element_size;
+  }
+  else { /* add up all the sizes */
+    element_size = 0;
+    contents_size = 0;
+    for (i = 0; i != n_elements; ++i)
+      contents_size += request2size(sizes[i]);
+  }
+
+  size = contents_size + array_size;
+
+  /*
+     Allocate the aggregate chunk.  First disable direct-mmapping so
+     malloc won't use it, since we would not be able to later
+     free/realloc space internal to a segregated mmap region.
+  */
+  was_enabled = use_mmap(m);
+  disable_mmap(m);
+  mem = internal_malloc(m, size - CHUNK_OVERHEAD);
+  if (was_enabled)
+    enable_mmap(m);
+  if (mem == 0)
+    return 0;
+
+  if (PREACTION(m)) return 0;
+  p = mem2chunk(mem);
+  remainder_size = chunksize(p);
+
+  assert(!is_mmapped(p));
+
+  if (opts & 0x2) {       /* optionally clear the elements */
+    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
+  }
+
+  /* If not provided, allocate the pointer array as final part of chunk */
+  if (marray == 0) {
+    size_t  array_chunk_size;
+    array_chunk = chunk_plus_offset(p, contents_size);
+    array_chunk_size = remainder_size - contents_size;
+    marray = (void**) (chunk2mem(array_chunk));
+    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
+    remainder_size = contents_size;
+  }
+
+  /* split out elements */
+  for (i = 0; ; ++i) {
+    marray[i] = chunk2mem(p);
+    if (i != n_elements-1) {
+      if (element_size != 0)
+        size = element_size;
+      else
+        size = request2size(sizes[i]);
+      remainder_size -= size;
+      set_size_and_pinuse_of_inuse_chunk(m, p, size);
+      p = chunk_plus_offset(p, size);
+    }
+    else { /* the final element absorbs any overallocation slop */
+      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
+      break;
+    }
+  }
+
+#if DEBUG
+  if (marray != chunks) {
+    /* final element must have exactly exhausted chunk */
+    if (element_size != 0) {
+      assert(remainder_size == element_size);
+    }
+    else {
+      assert(remainder_size == request2size(sizes[i]));
+    }
+    check_inuse_chunk(m, mem2chunk(marray));
+  }
+  for (i = 0; i != n_elements; ++i)
+    check_inuse_chunk(m, mem2chunk(marray[i]));
+
+#endif /* DEBUG */
+
+  POSTACTION(m);
+  return marray;
+}
+
+
+/* -------------------------- public routines ---------------------------- */
+
+#if !ONLY_MSPACES
+
+void* dlmalloc(size_t bytes) {
+  /*
+     Basic algorithm:
+     If a small request (< 256 bytes minus per-chunk overhead):
+       1. If one exists, use a remainderless chunk in associated smallbin.
+          (Remainderless means that there are too few excess bytes to
+          represent as a chunk.)
+       2. If it is big enough, use the dv chunk, which is normally the
+          chunk adjacent to the one used for the most recent small request.
+       3. If one exists, split the smallest available chunk in a bin,
+          saving remainder in dv.
+       4. If it is big enough, use the top chunk.
+       5. If available, get memory from system and use it
+     Otherwise, for a large request:
+       1. Find the smallest available binned chunk that fits, and use it
+          if it is better fitting than dv chunk, splitting if necessary.
+       2. If better fitting than any binned chunk, use the dv chunk.
+       3. If it is big enough, use the top chunk.
+       4. If request size >= mmap threshold, try to directly mmap this chunk.
+       5. If available, get memory from system and use it
+
+     The ugly goto's here ensure that postaction occurs along all paths.
+  */
+
+  if (!PREACTION(gm)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = gm->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+        mchunkptr b, p;
+        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+        b = smallbin_at(gm, idx);
+        p = b->fd;
+        assert(chunksize(p) == small_index2size(idx));
+        unlink_first_small_chunk(gm, b, p, idx);
+        set_inuse_and_pinuse(gm, p, small_index2size(idx));
+        mem = chunk2mem(p);
+        check_malloced_chunk(gm, mem, nb);
+        goto postaction;
+      }
+
+      else if (nb > gm->dvsize) {
+        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+          mchunkptr b, p, r;
+          size_t rsize;
+          bindex_t i;
+          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+          binmap_t leastbit = least_bit(leftbits);
+          compute_bit2idx(leastbit, i);
+          b = smallbin_at(gm, i);
+          p = b->fd;
+          assert(chunksize(p) == small_index2size(i));
+          unlink_first_small_chunk(gm, b, p, i);
+          rsize = small_index2size(i) - nb;
+          /* Fit here cannot be remainderless if 4byte sizes */
+          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+            set_inuse_and_pinuse(gm, p, small_index2size(i));
+          else {
+            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+            r = chunk_plus_offset(p, nb);
+            set_size_and_pinuse_of_free_chunk(r, rsize);
+            replace_dv(gm, r, rsize);
+          }
+          mem = chunk2mem(p);
+          check_malloced_chunk(gm, mem, nb);
+          goto postaction;
+        }
+
+        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
+          check_malloced_chunk(gm, mem, nb);
+          goto postaction;
+        }
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
+        check_malloced_chunk(gm, mem, nb);
+        goto postaction;
+      }
+    }
+
+    if (nb <= gm->dvsize) {
+      size_t rsize = gm->dvsize - nb;
+      mchunkptr p = gm->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
+        gm->dvsize = rsize;
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      }
+      else { /* exhaust dv */
+        size_t dvs = gm->dvsize;
+        gm->dvsize = 0;
+        gm->dv = 0;
+        set_inuse_and_pinuse(gm, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < gm->topsize) { /* Split top */
+      size_t rsize = gm->topsize -= nb;
+      mchunkptr p = gm->top;
+      mchunkptr r = gm->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(gm, gm->top);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(gm, nb);
+
+  postaction:
+    POSTACTION(gm);
+    return mem;
+  }
+
+  return 0;
+}
+
+void dlfree(void* mem) {
+  /*
+     Consolidate freed chunks with preceeding or succeeding bordering
+     free chunks, if they exist, and then place in a bin.  Intermixed
+     with special cases for top, dv, mmapped chunks, and usage errors.
+  */
+
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+#else /* FOOTERS */
+#define fm gm
+#endif /* FOOTERS */
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+        size_t psize = chunksize(p);
+        mchunkptr next = chunk_plus_offset(p, psize);
+        if (!pinuse(p)) {
+          size_t prevsize = p->prev_foot;
+          if ((prevsize & IS_MMAPPED_BIT) != 0) {
+            prevsize &= ~IS_MMAPPED_BIT;
+            psize += prevsize + MMAP_FOOT_PAD;
+            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+              fm->footprint -= psize;
+            goto postaction;
+          }
+          else {
+            mchunkptr prev = chunk_minus_offset(p, prevsize);
+            psize += prevsize;
+            p = prev;
+            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+              if (p != fm->dv) {
+                unlink_chunk(fm, p, prevsize);
+              }
+              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+                fm->dvsize = psize;
+                set_free_with_pinuse(p, psize, next);
+                goto postaction;
+              }
+            }
+            else
+              goto erroraction;
+          }
+        }
+
+        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+          if (!cinuse(next)) {  /* consolidate forward */
+            if (next == fm->top) {
+              size_t tsize = fm->topsize += psize;
+              fm->top = p;
+              p->head = tsize | PINUSE_BIT;
+              if (p == fm->dv) {
+                fm->dv = 0;
+                fm->dvsize = 0;
+              }
+              if (should_trim(fm, tsize))
+                sys_trim(fm, 0);
+              goto postaction;
+            }
+            else if (next == fm->dv) {
+              size_t dsize = fm->dvsize += psize;
+              fm->dv = p;
+              set_size_and_pinuse_of_free_chunk(p, dsize);
+              goto postaction;
+            }
+            else {
+              size_t nsize = chunksize(next);
+              psize += nsize;
+              unlink_chunk(fm, next, nsize);
+              set_size_and_pinuse_of_free_chunk(p, psize);
+              if (p == fm->dv) {
+                fm->dvsize = psize;
+                goto postaction;
+              }
+            }
+          }
+          else
+            set_free_with_pinuse(p, psize, next);
+          insert_chunk(fm, p, psize);
+          check_free_chunk(fm, p);
+          goto postaction;
+        }
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+#if !FOOTERS
+#undef fm
+#endif /* FOOTERS */
+}
+
+void* dlcalloc(size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+        (req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = dlmalloc(req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* dlrealloc(void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return dlmalloc(bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    dlfree(oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if ! FOOTERS
+    mstate m = gm;
+#else /* FOOTERS */
+    mstate m = get_mstate_for(mem2chunk(oldmem));
+    if (!ok_magic(m)) {
+      USAGE_ERROR_ACTION(m, oldmem);
+      return 0;
+    }
+#endif /* FOOTERS */
+    return internal_realloc(m, oldmem, bytes);
+  }
+}
+
+void* dlmemalign(size_t alignment, size_t bytes) {
+  return internal_memalign(gm, alignment, bytes);
+}
+
+void** dlindependent_calloc(size_t n_elements, size_t elem_size,
+                                 void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  return ialloc(gm, n_elements, &sz, 3, chunks);
+}
+
+void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
+                                   void* chunks[]) {
+  return ialloc(gm, n_elements, sizes, 0, chunks);
+}
+
+void* dlvalloc(size_t bytes) {
+  size_t pagesz;
+  init_mparams();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, bytes);
+}
+
+void* dlpvalloc(size_t bytes) {
+  size_t pagesz;
+  init_mparams();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - 
SIZE_T_ONE));
+}
+
+int dlmalloc_trim(size_t pad) {
+  int result = 0;
+  if (!PREACTION(gm)) {
+    result = sys_trim(gm, pad);
+    POSTACTION(gm);
+  }
+  return result;
+}
+
+size_t dlmalloc_footprint(void) {
+  return gm->footprint;
+}
+
+size_t dlmalloc_max_footprint(void) {
+  return gm->max_footprint;
+}
+
+#if !NO_MALLINFO
+struct mallinfo dlmallinfo(void) {
+  return internal_mallinfo(gm);
+}
+#endif /* NO_MALLINFO */
+
+void dlmalloc_stats() {
+  internal_malloc_stats(gm);
+}
+
+size_t dlmalloc_usable_size(void* mem) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    if (cinuse(p))
+      return chunksize(p) - overhead_for(p);
+  }
+  return 0;
+}
+
+int dlmallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* !ONLY_MSPACES */
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+#if MSPACES
+
+static mstate init_user_mstate(char* tbase, size_t tsize) {
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  mchunkptr mn;
+  mchunkptr msp = align_as_chunk(tbase);
+  mstate m = (mstate)(chunk2mem(msp));
+  memset(m, 0, msize);
+  INITIAL_LOCK(&m->mutex);
+  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
+  m->seg.base = m->least_addr = tbase;
+  m->seg.size = m->footprint = m->max_footprint = tsize;
+  m->magic = mparams.magic;
+  m->mflags = mparams.default_mflags;
+  disable_contiguous(m);
+  init_bins(m);
+  mn = next_chunk(mem2chunk(m));
+  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+  check_top_chunk(m, m->top);
+  return m;
+}
+
+mspace create_mspace(size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  init_mparams(); /* Ensure pagesize etc initialized */
+
+  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    size_t rs = ((capacity == 0)? mparams.granularity :
+                 (capacity + TOP_FOOT_SIZE + msize));
+    size_t tsize = granularity_align(rs);
+    char* tbase = (char*)(CALL_MMAP(tsize));
+    if (tbase != CMFAIL) {
+      m = init_user_mstate(tbase, tsize);
+      set_segment_flags(&m->seg, IS_MMAPPED_BIT);
+      set_lock(m, locked);
+    }
+  }
+  return (mspace)m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  init_mparams(); /* Ensure pagesize etc initialized */
+
+  if (capacity > msize + TOP_FOOT_SIZE &&
+      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    m = init_user_mstate((char*)base, capacity);
+    set_segment_flags(&m->seg, EXTERN_BIT);
+    set_lock(m, locked);
+  }
+  return (mspace)m;
+}
+
+size_t destroy_mspace(mspace msp) {
+  size_t freed = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    msegmentptr sp = &ms->seg;
+    while (sp != 0) {
+      char* base = sp->base;
+      size_t size = sp->size;
+      flag_t flag = get_segment_flags(sp);
+      sp = sp->next;
+      if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&
+          CALL_MUNMAP(base, size) == 0)
+        freed += size;
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return freed;
+}
+
+/*
+  mspace versions of routines are near-clones of the global
+  versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (!PREACTION(ms)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = ms->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+        mchunkptr b, p;
+        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+        b = smallbin_at(ms, idx);
+        p = b->fd;
+        assert(chunksize(p) == small_index2size(idx));
+        unlink_first_small_chunk(ms, b, p, idx);
+        set_inuse_and_pinuse(ms, p, small_index2size(idx));
+        mem = chunk2mem(p);
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+
+      else if (nb > ms->dvsize) {
+        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+          mchunkptr b, p, r;
+          size_t rsize;
+          bindex_t i;
+          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+          binmap_t leastbit = least_bit(leftbits);
+          compute_bit2idx(leastbit, i);
+          b = smallbin_at(ms, i);
+          p = b->fd;
+          assert(chunksize(p) == small_index2size(i));
+          unlink_first_small_chunk(ms, b, p, i);
+          rsize = small_index2size(i) - nb;
+          /* Fit here cannot be remainderless if 4byte sizes */
+          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+            set_inuse_and_pinuse(ms, p, small_index2size(i));
+          else {
+            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+            r = chunk_plus_offset(p, nb);
+            set_size_and_pinuse_of_free_chunk(r, rsize);
+            replace_dv(ms, r, rsize);
+          }
+          mem = chunk2mem(p);
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+
+        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+    }
+
+    if (nb <= ms->dvsize) {
+      size_t rsize = ms->dvsize - nb;
+      mchunkptr p = ms->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+        ms->dvsize = rsize;
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      }
+      else { /* exhaust dv */
+        size_t dvs = ms->dvsize;
+        ms->dvsize = 0;
+        ms->dv = 0;
+        set_inuse_and_pinuse(ms, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < ms->topsize) { /* Split top */
+      size_t rsize = ms->topsize -= nb;
+      mchunkptr p = ms->top;
+      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(ms, ms->top);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(ms, nb);
+
+  postaction:
+    POSTACTION(ms);
+    return mem;
+  }
+
+  return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+        size_t psize = chunksize(p);
+        mchunkptr next = chunk_plus_offset(p, psize);
+        if (!pinuse(p)) {
+          size_t prevsize = p->prev_foot;
+          if ((prevsize & IS_MMAPPED_BIT) != 0) {
+            prevsize &= ~IS_MMAPPED_BIT;
+            psize += prevsize + MMAP_FOOT_PAD;
+            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+              fm->footprint -= psize;
+            goto postaction;
+          }
+          else {
+            mchunkptr prev = chunk_minus_offset(p, prevsize);
+            psize += prevsize;
+            p = prev;
+            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+              if (p != fm->dv) {
+                unlink_chunk(fm, p, prevsize);
+              }
+              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+                fm->dvsize = psize;
+                set_free_with_pinuse(p, psize, next);
+                goto postaction;
+              }
+            }
+            else
+              goto erroraction;
+          }
+        }
+
+        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+          if (!cinuse(next)) {  /* consolidate forward */
+            if (next == fm->top) {
+              size_t tsize = fm->topsize += psize;
+              fm->top = p;
+              p->head = tsize | PINUSE_BIT;
+              if (p == fm->dv) {
+                fm->dv = 0;
+                fm->dvsize = 0;
+              }
+              if (should_trim(fm, tsize))
+                sys_trim(fm, 0);
+              goto postaction;
+            }
+            else if (next == fm->dv) {
+              size_t dsize = fm->dvsize += psize;
+              fm->dv = p;
+              set_size_and_pinuse_of_free_chunk(p, dsize);
+              goto postaction;
+            }
+            else {
+              size_t nsize = chunksize(next);
+              psize += nsize;
+              unlink_chunk(fm, next, nsize);
+              set_size_and_pinuse_of_free_chunk(p, psize);
+              if (p == fm->dv) {
+                fm->dvsize = psize;
+                goto postaction;
+              }
+            }
+          }
+          else
+            set_free_with_pinuse(p, psize, next);
+          insert_chunk(fm, p, psize);
+          check_free_chunk(fm, p);
+          goto postaction;
+        }
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+        (req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = internal_malloc(ms, req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    mspace_free(msp, oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if FOOTERS
+    mchunkptr p  = mem2chunk(oldmem);
+    mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(ms)) {
+      USAGE_ERROR_ACTION(ms,ms);
+      return 0;
+    }
+    return internal_realloc(ms, oldmem, bytes);
+  }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return internal_memalign(ms, alignment, bytes);
+}
+
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+                                 size_t elem_size, void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, &sz, 3, chunks);
+}
+
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+                                   size_t sizes[], void* chunks[]) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, sizes, 0, chunks);
+}
+
+int mspace_trim(mspace msp, size_t pad) {
+  int result = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    if (!PREACTION(ms)) {
+      result = sys_trim(ms, pad);
+      POSTACTION(ms);
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+void mspace_malloc_stats(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    internal_malloc_stats(ms);
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+}
+
+size_t mspace_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->footprint;
+  }
+  USAGE_ERROR_ACTION(ms,ms);
+  return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->max_footprint;
+  }
+  USAGE_ERROR_ACTION(ms,ms);
+  return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+int mspace_mallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* MSPACES */
+
+/* -------------------- Alternative MORECORE functions ------------------- */
+
+/*
+  Guidelines for creating a custom version of MORECORE:
+
+  * For best performance, MORECORE should allocate in multiples of pagesize.
+  * MORECORE may allocate more memory than requested. (Or even less,
+      but this will usually result in a malloc failure.)
+  * MORECORE must not allocate memory when given argument zero, but
+      instead return one past the end address of memory from previous
+      nonzero call.
+  * For best performance, consecutive calls to MORECORE with positive
+      arguments should return increasing addresses, indicating that
+      space has been contiguously extended.
+  * Even though consecutive calls to MORECORE need not return contiguous
+      addresses, it must be OK for malloc'ed chunks to span multiple
+      regions in those cases where they do happen to be contiguous.
+  * MORECORE need not handle negative arguments -- it may instead
+      just return MFAIL when given negative arguments.
+      Negative arguments are always multiples of pagesize. MORECORE
+      must not misinterpret negative args as large positive unsigned
+      args. You can suppress all such calls from even occurring by defining
+      MORECORE_CANNOT_TRIM,
+
+  As an example alternative MORECORE, here is a custom allocator
+  kindly contributed for pre-OSX macOS.  It uses virtually but not
+  necessarily physically contiguous non-paged memory (locked in,
+  present and won't get swapped out).  You can use it by uncommenting
+  this section, adding some #includes, and setting up the appropriate
+  defines above:
+
+      #define MORECORE osMoreCore
+
+  There is also a shutdown routine that should somehow be called for
+  cleanup upon program exit.
+
+  #define MAX_POOL_ENTRIES 100
+  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)
+  static int next_os_pool;
+  void *our_os_pools[MAX_POOL_ENTRIES];
+
+  void *osMoreCore(int size)
+  {
+    void *ptr = 0;
+    static void *sbrk_top = 0;
+
+    if (size > 0)
+    {
+      if (size < MINIMUM_MORECORE_SIZE)
+         size = MINIMUM_MORECORE_SIZE;
+      if (CurrentExecutionLevel() == kTaskLevel)
+         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+      if (ptr == 0)
+      {
+        return (void *) MFAIL;
+      }
+      // save ptrs so they can be freed during cleanup
+      our_os_pools[next_os_pool] = ptr;
+      next_os_pool++;
+      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+      sbrk_top = (char *) ptr + size;
+      return ptr;
+    }
+    else if (size < 0)
+    {
+      // we don't currently support shrink behavior
+      return (void *) MFAIL;
+    }
+    else
+    {
+      return sbrk_top;
+    }
+  }
+
+  // cleanup any allocated memory pools
+  // called as last thing before shutting down driver
+
+  void osCleanupMem(void)
+  {
+    void **ptr;
+
+    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+      if (*ptr)
+      {
+         PoolDeallocate(*ptr);
+         *ptr = 0;
+      }
+  }
+
+*/
+
+
+/* -----------------------------------------------------------------------
+History:
+    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)
+      * Add max_footprint functions
+      * Ensure all appropriate literals are size_t
+      * Fix conditional compilation problem for some #define settings
+      * Avoid concatenating segments with the one provided
+        in create_mspace_with_base
+      * Rename some variables to avoid compiler shadowing warnings
+      * Use explicit lock initialization.
+      * Better handling of sbrk interference.
+      * Simplify and fix segment insertion, trimming and mspace_destroy
+      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
+      * Thanks especially to Dennis Flanagan for help on these.
+
+    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)
+      * Fix memalign brace error.
+
+    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)
+      * Fix improper #endif nesting in C++
+      * Add explicit casts needed for C++
+
+    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)
+      * Use trees for large bins
+      * Support mspaces
+      * Use segments to unify sbrk-based and mmap-based system allocation,
+        removing need for emulation on most platforms without sbrk.
+      * Default safety checks
+      * Optional footer checks. Thanks to William Robertson for the idea.
+      * Internal code refactoring
+      * Incorporate suggestions and platform-specific changes.
+        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
+        Aaron Bachmann,  Emery Berger, and others.
+      * Speed up non-fastbin processing enough to remove fastbins.
+      * Remove useless cfree() to avoid conflicts with other apps.
+      * Remove internal memcpy, memset. Compilers handle builtins better.
+      * Remove some options that no one ever used and rename others.
+
+    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)
+      * Fix malloc_state bitmap array misdeclaration
+
+    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)
+      * Allow tuning of FIRST_SORTED_BIN_SIZE
+      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+      * Better detection and support for non-contiguousness of MORECORE.
+        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+      * Bypass most of malloc if no frees. Thanks To Emery Berger.
+      * Fix freeing of old top non-contiguous chunk im sysmalloc.
+      * Raised default trim and map thresholds to 256K.
+      * Fix mmap-related #defines. Thanks to Lubos Lunak.
+      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+      * Branch-free bin calculation
+      * Default trim and mmap thresholds now 256K.
+
+    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+      * Introduce independent_comalloc and independent_calloc.
+        Thanks to Michael Pachos for motivation and help.
+      * Make optional .h file available
+      * Allow > 2GB requests on 32bit systems.
+      * new WIN32 sbrk, mmap, munmap, lock code from <address@hidden>.
+        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+        and Anonymous.
+      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+        helping test this.)
+      * memalign: check alignment arg
+      * realloc: don't try to shift chunks backwards, since this
+        leads to  more fragmentation in some programs and doesn't
+        seem to help in any others.
+      * Collect all cases in malloc requiring system memory into sysmalloc
+      * Use mmap as backup to sbrk
+      * Place all internal state in malloc_state
+      * Introduce fastbins (although similar to 2.5.1)
+      * Many minor tunings and cosmetic improvements
+      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+        Thanks to Tony E. Bennett <address@hidden> and others.
+      * Include errno.h to support default failure action.
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+          (e.g. WIN32 platforms)
+         * Cleanup header file inclusion for WIN32 platforms
+         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+           memory allocation routines
+         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+           usage of 'assert' in non-WIN32 code
+         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+           avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+        foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+        Wolfram Gloger (address@hidden).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  address@hidden
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+        avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+        (address@hidden) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+        courtesy of Wolfram Gloger (address@hidden).
+      * Added macros etc., allowing use in linux libc from
+        H.J. Lu (address@hidden)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+        the work required to undo bad preallocations exceeds
+        the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+        no scheme using them consistently outperforms those that don't
+        given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+        Paul Wilson (address@hidden) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+        (address@hidden).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from address@hidden
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+         (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+          from address@hidden
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+          with gcc & native cc (hp, dec only) allowing
+          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+         structure of old version,  but most details differ.)
+ 
+*/

Index: libffi/src/pa/hpux32.S
===================================================================
RCS file: libffi/src/pa/hpux32.S
diff -N libffi/src/pa/hpux32.S
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libffi/src/pa/hpux32.S      30 Nov 2007 20:59:57 -0000      1.1
@@ -0,0 +1,367 @@
+/* -----------------------------------------------------------------------
+   hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc.
+   based on src/pa/linux.S
+
+   HP-UX PA Foreign Function Interface
+
+   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
+#include <fficonfig.h>
+#include <ffi.h>
+
+       .LEVEL 1.1
+       .SPACE  $PRIVATE$
+       .IMPORT $global$,DATA
+       .IMPORT $$dyncall,MILLICODE
+       .SUBSPA $DATA$
+       .align  4
+
+       /* void ffi_call_pa32(void (*)(char *, extended_cif *),
+                              extended_cif *ecif,
+                              unsigned bytes,
+                              unsigned flags,
+                              unsigned *rvalue,
+                              void (*fn)());
+        */
+
+       .export ffi_call_pa32,ENTRY,PRIV_LEV=3
+       .import ffi_prep_args_pa32,CODE
+
+       .SPACE  $TEXT$
+       .SUBSPA $CODE$
+       .align  4
+
+L$FB1
+ffi_call_pa32
+       .proc
+       .callinfo       FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
+       .entry
+       stw     %rp, -20(%sp)
+       copy    %r3, %r1
+L$CFI11
+       copy    %sp, %r3
+L$CFI12
+
+       /* Setup the stack for calling prep_args...
+          We want the stack to look like this:
+
+          [ Previous stack                            ] <- %r3
+
+          [ 64-bytes register save area               ] <- %r4
+
+          [ Stack space for actual call, passed as    ] <- %arg0
+          [     arg0 to ffi_prep_args_pa32           ]
+
+          [ Stack for calling prep_args               ] <- %sp
+        */
+
+       stwm    %r1, 64(%sp)
+       stw     %r4, 12(%r3)
+L$CFI13
+       copy    %sp, %r4
+
+       addl    %arg2, %r4, %arg0       ; arg stack
+       stw     %arg3, -48(%r3)         ; save flags we need it later
+
+       /* Call prep_args:
+          %arg0(stack) -- set up above
+          %arg1(ecif)  -- same as incoming param
+          %arg2(bytes) -- same as incoming param */
+       bl      ffi_prep_args_pa32,%r2
+       ldo     64(%arg0), %sp
+       ldo     -64(%sp), %sp
+
+       /* now %sp should point where %arg0 was pointing.  */
+
+       /* Load the arguments that should be passed in registers
+          The fp args are loaded by the prep_args function.  */
+       ldw     -36(%sp), %arg0
+       ldw     -40(%sp), %arg1
+       ldw     -44(%sp), %arg2
+       ldw     -48(%sp), %arg3
+
+       /* in case the function is going to return a structure
+          we need to give it a place to put the result.  */
+       ldw     -52(%r3), %ret0         ; %ret0 <- rvalue
+       ldw     -56(%r3), %r22          ; %r22 <- function to call
+       bl      $$dyncall, %r31         ; Call the user function
+       copy    %r31, %rp
+
+       /* Prepare to store the result; we need to recover flags and rvalue.  */
+       ldw     -48(%r3), %r21          ; r21 <- flags
+       ldw     -52(%r3), %r20          ; r20 <- rvalue
+
+       /* Store the result according to the return type.  The most
+          likely types should come first.  */
+
+L$checkint
+       comib,<>,n FFI_TYPE_INT, %r21, L$checkint8
+       b       L$done
+       stw     %ret0, 0(%r20)
+
+L$checkint8
+       comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16
+       b       L$done
+       stb     %ret0, 0(%r20)
+
+L$checkint16
+       comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl
+       b       L$done
+       sth     %ret0, 0(%r20)
+
+L$checkdbl
+       comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat
+       b       L$done
+       fstd    %fr4,0(%r20)
+
+L$checkfloat
+       comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll
+       b       L$done
+       fstw    %fr4L,0(%r20)
+
+L$checkll
+       comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2
+       stw     %ret0, 0(%r20)
+       b       L$done
+       stw     %ret1, 4(%r20)
+
+L$checksmst2
+       comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3
+       /* 2-byte structs are returned in ret0 as ????xxyy.  */
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret0, 0(%r20)
+
+L$checksmst3
+       comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4
+       /* 3-byte structs are returned in ret0 as ??xxyyzz.  */
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret0, 0(%r20)
+
+L$checksmst4
+       comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5
+       /* 4-byte structs are returned in ret0 as wwxxyyzz.  */
+       extru   %ret0, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret0, 0(%r20)
+
+L$checksmst5
+       comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6
+       /* 5 byte values are returned right justified:
+             ret0     ret1
+          5: ??????aa bbccddee */
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret1, 0(%r20)
+
+L$checksmst6
+       comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7
+       /* 6 byte values are returned right justified:
+             ret0     ret1
+          6: ????aabb ccddeeff */
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret1, 0(%r20)
+
+L$checksmst7
+       comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8
+       /* 7 byte values are returned right justified:
+             ret0     ret1
+          7: ??aabbcc ddeeffgg */
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       b       L$done
+       stb     %ret1, 0(%r20)
+
+L$checksmst8
+       comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done
+       /* 8 byte values are returned right justified:
+             ret0     ret1
+          8: aabbccdd eeffgghh */
+       extru   %ret0, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret0, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stbs,ma %ret0, 1(%r20)
+       extru   %ret1, 7, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 15, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       extru   %ret1, 23, 8, %r22
+       stbs,ma %r22, 1(%r20)
+       stb     %ret1, 0(%r20)
+
+L$done
+       /* all done, return */
+       copy    %r4, %sp        ; pop arg stack
+       ldw     12(%r3), %r4
+       ldwm    -64(%sp), %r3   ; .. and pop stack
+       ldw     -20(%sp), %rp
+       bv      %r0(%rp)
+       nop
+       .exit
+       .procend
+L$FE1
+
+       /* void ffi_closure_pa32(void);
+          Called with closure argument in %r21 */
+
+       .SPACE $TEXT$
+       .SUBSPA $CODE$
+       .export ffi_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR
+       .import ffi_closure_inner_pa32,CODE
+       .align 4
+L$FB2
+ffi_closure_pa32
+       .proc
+       .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
+       .entry
+
+       stw     %rp, -20(%sp)
+       copy    %r3, %r1
+L$CFI21
+       copy    %sp, %r3
+L$CFI22
+       stwm    %r1, 64(%sp)
+
+       /* Put arguments onto the stack and call ffi_closure_inner.  */
+       stw     %arg0, -36(%r3)
+       stw     %arg1, -40(%r3)
+       stw     %arg2, -44(%r3)
+       stw     %arg3, -48(%r3)
+
+       copy    %r21, %arg0
+       bl      ffi_closure_inner_pa32, %r2
+       copy    %r3, %arg1
+       ldwm    -64(%sp), %r3
+       ldw     -20(%sp), %rp
+       ldw     -36(%sp), %ret0
+       bv      %r0(%rp)
+       ldw     -40(%sp), %ret1
+       .exit
+       .procend
+L$FE2:
+
+       .SPACE $PRIVATE$
+       .SUBSPA $DATA$
+
+       .align 4
+       .EXPORT _GLOBAL__F_ffi_call_pa32,DATA
+_GLOBAL__F_ffi_call_pa32
+L$frame1:
+       .word   L$ECIE1-L$SCIE1 ;# Length of Common Information Entry
+L$SCIE1:
+       .word   0x0     ;# CIE Identifier Tag
+       .byte   0x1     ;# CIE Version
+       .ascii "\0"     ;# CIE Augmentation
+       .uleb128 0x1    ;# CIE Code Alignment Factor
+       .sleb128 4      ;# CIE Data Alignment Factor
+       .byte   0x2     ;# CIE RA Column
+       .byte   0xc     ;# DW_CFA_def_cfa
+       .uleb128 0x1e
+       .uleb128 0x0
+       .align 4
+L$ECIE1:
+L$SFDE1:
+       .word   L$EFDE1-L$ASFDE1        ;# FDE Length
+L$ASFDE1:
+       .word   L$ASFDE1-L$frame1       ;# FDE CIE offset
+       .word   L$FB1   ;# FDE initial location
+       .word   L$FE1-L$FB1     ;# FDE address range
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI11-L$FB1
+       .byte   0x83    ;# DW_CFA_offset, column 0x3
+       .uleb128 0x0
+       .byte   0x11    ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
+       .uleb128 0x2
+       .sleb128 -5
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI12-L$CFI11
+       .byte   0xd     ;# DW_CFA_def_cfa_register = r3
+       .uleb128 0x3
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI13-L$CFI12
+       .byte   0x84    ;# DW_CFA_offset, column 0x4
+       .uleb128 0x3
+
+       .align 4
+L$EFDE1:
+
+L$SFDE2:
+       .word   L$EFDE2-L$ASFDE2        ;# FDE Length
+L$ASFDE2:
+       .word   L$ASFDE2-L$frame1       ;# FDE CIE offset
+       .word   L$FB2   ;# FDE initial location
+       .word   L$FE2-L$FB2     ;# FDE address range
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI21-L$FB2
+       .byte   0x83    ;# DW_CFA_offset, column 0x3
+       .uleb128 0x0
+       .byte   0x11    ;# DW_CFA_offset_extended_sf
+       .uleb128 0x2
+       .sleb128 -5
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI22-L$CFI21
+       .byte   0xd     ;# DW_CFA_def_cfa_register = r3
+       .uleb128 0x3
+
+       .align 4
+L$EFDE2:

Index: libffi/src/x86/darwin.S
===================================================================
RCS file: libffi/src/x86/darwin.S
diff -N libffi/src/x86/darwin.S
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libffi/src/x86/darwin.S     30 Nov 2007 20:59:58 -0000      1.1
@@ -0,0 +1,403 @@
+/* -----------------------------------------------------------------------
+   sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005  Red Hat, Inc.
+   
+   X86 Foreign Function Interface 
+
+   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 CYGNUS SOLUTIONS 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.
+   ----------------------------------------------------------------------- */
+
+#ifndef __x86_64__
+
+#define LIBFFI_ASM     
+#include <fficonfig.h>
+#include <ffi.h>
+
+.text
+
+.globl _ffi_prep_args
+
+       .align 4
+.globl _ffi_call_SYSV
+
+_ffi_call_SYSV:
+.LFB1:
+        pushl %ebp
+.LCFI0:
+        movl  %esp,%ebp
+.LCFI1:
+        subl $8,%esp
+       /* Make room for all of the new args.  */
+       movl  16(%ebp),%ecx
+       subl  %ecx,%esp
+
+       movl  %esp,%eax
+
+       /* Place all of the ffi_prep_args in position  */
+       subl  $8,%esp
+       pushl 12(%ebp)
+       pushl %eax
+       call  *8(%ebp)
+
+       /* Return stack to previous state and call the function  */
+       addl  $16,%esp  
+
+       call  *28(%ebp)
+
+       /* Remove the space we pushed for the args  */
+       movl  16(%ebp),%ecx
+       addl  %ecx,%esp
+
+       /* Load %ecx with the return type code  */
+       movl  20(%ebp),%ecx     
+
+       /* If the return value pointer is NULL, assume no return value.  */
+       cmpl  $0,24(%ebp)
+       jne   retint
+
+       /* Even if there is no space for the return value, we are 
+          obliged to handle floating-point values.  */
+       cmpl  $FFI_TYPE_FLOAT,%ecx
+       jne   noretval
+       fstp  %st(0)
+
+        jmp   epilogue
+
+retint:
+       cmpl  $FFI_TYPE_INT,%ecx
+       jne   retfloat
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       movl  %eax,0(%ecx)
+       jmp   epilogue
+
+retfloat:
+       cmpl  $FFI_TYPE_FLOAT,%ecx
+       jne   retdouble
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       fstps (%ecx)
+       jmp   epilogue
+
+retdouble:
+       cmpl  $FFI_TYPE_DOUBLE,%ecx
+       jne   retlongdouble
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       fstpl (%ecx)
+       jmp   epilogue
+
+retlongdouble:
+       cmpl  $FFI_TYPE_LONGDOUBLE,%ecx
+       jne   retint64
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       fstpt (%ecx)
+       jmp   epilogue
+       
+retint64:      
+       cmpl  $FFI_TYPE_SINT64,%ecx
+        jne   retstruct1b
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       movl  %eax,0(%ecx)
+       movl  %edx,4(%ecx)
+       jmp   epilogue
+       
+retstruct1b:   
+       cmpl  $FFI_TYPE_SINT8,%ecx
+        jne   retstruct2b
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       movb  %al,0(%ecx)
+       jmp   epilogue
+
+retstruct2b:   
+       cmpl  $FFI_TYPE_SINT16,%ecx
+        jne   retstruct
+       /* Load %ecx with the pointer to storage for the return value  */
+       movl  24(%ebp),%ecx     
+       movw  %ax,0(%ecx)
+       jmp   epilogue
+
+retstruct:
+       cmpl  $FFI_TYPE_STRUCT,%ecx
+        jne   noretval
+       /* Nothing to do!  */
+        addl $4,%esp
+        popl %ebp
+        ret
+
+noretval:
+epilogue:
+        addl $8,%esp
+        movl %ebp,%esp
+        popl %ebp
+        ret
+.LFE1:
+.ffi_call_SYSV_end:
+
+       .align  4
+FFI_HIDDEN (ffi_closure_SYSV)
+.globl _ffi_closure_SYSV
+
+_ffi_closure_SYSV:
+.LFB2:
+       pushl   %ebp
+.LCFI2:
+       movl    %esp, %ebp
+.LCFI3:
+       subl    $40, %esp
+       leal    -24(%ebp), %edx
+       movl    %edx, -12(%ebp) /* resp */
+       leal    8(%ebp), %edx
+       movl    %edx, 4(%esp)   /* args = __builtin_dwarf_cfa () */
+       leal    -12(%ebp), %edx
+       movl    %edx, (%esp)    /* &resp */
+       movl    %ebx, 8(%esp)
+.LCFI7:
+       call    L_ffi_closure_SYSV_inner$stub
+       movl    8(%esp), %ebx
+       movl    -12(%ebp), %ecx
+       cmpl    $FFI_TYPE_INT, %eax
+       je      .Lcls_retint
+       cmpl    $FFI_TYPE_FLOAT, %eax
+       je      .Lcls_retfloat
+       cmpl    $FFI_TYPE_DOUBLE, %eax
+       je      .Lcls_retdouble
+       cmpl    $FFI_TYPE_LONGDOUBLE, %eax
+       je      .Lcls_retldouble
+       cmpl    $FFI_TYPE_SINT64, %eax
+       je      .Lcls_retllong
+       cmpl    $FFI_TYPE_SINT8, %eax
+       je      .Lcls_retstruct1
+       cmpl    $FFI_TYPE_SINT16, %eax
+       je      .Lcls_retstruct2
+       cmpl    $FFI_TYPE_STRUCT, %eax
+       je      .Lcls_retstruct
+.Lcls_epilogue:
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+.Lcls_retint:
+       movl    (%ecx), %eax
+       jmp     .Lcls_epilogue
+.Lcls_retfloat:
+       flds    (%ecx)
+       jmp     .Lcls_epilogue
+.Lcls_retdouble:
+       fldl    (%ecx)
+       jmp     .Lcls_epilogue
+.Lcls_retldouble:
+       fldt    (%ecx)
+       jmp     .Lcls_epilogue
+.Lcls_retllong:
+       movl    (%ecx), %eax
+       movl    4(%ecx), %edx
+       jmp     .Lcls_epilogue
+.Lcls_retstruct1:
+       movsbl  (%ecx), %eax
+       jmp     .Lcls_epilogue
+.Lcls_retstruct2:
+       movswl  (%ecx), %eax
+       jmp     .Lcls_epilogue
+.Lcls_retstruct:
+       lea -8(%ebp),%esp
+       movl    %ebp, %esp
+       popl    %ebp
+       ret $4
+.LFE2:
+
+#if !FFI_NO_RAW_API
+
+#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
+#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
+#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
+#define CIF_FLAGS_OFFSET 20
+
+       .align  4
+FFI_HIDDEN (ffi_closure_raw_SYSV)
+.globl _ffi_closure_raw_SYSV
+
+_ffi_closure_raw_SYSV:
+.LFB3:
+       pushl   %ebp
+.LCFI4:
+       movl    %esp, %ebp
+.LCFI5:
+       pushl   %esi
+.LCFI6:
+       subl    $36, %esp
+       movl    RAW_CLOSURE_CIF_OFFSET(%eax), %esi       /* closure->cif */
+       movl    RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data 
*/
+       movl    %edx, 12(%esp)  /* user_data */
+       leal    8(%ebp), %edx   /* __builtin_dwarf_cfa () */
+       movl    %edx, 8(%esp)   /* raw_args */
+       leal    -24(%ebp), %edx
+       movl    %edx, 4(%esp)   /* &res */
+       movl    %esi, (%esp)    /* cif */
+       call    *RAW_CLOSURE_FUN_OFFSET(%eax)            /* closure->fun */
+       movl    CIF_FLAGS_OFFSET(%esi), %eax             /* rtype */
+       cmpl    $FFI_TYPE_INT, %eax
+       je      .Lrcls_retint
+       cmpl    $FFI_TYPE_FLOAT, %eax
+       je      .Lrcls_retfloat
+       cmpl    $FFI_TYPE_DOUBLE, %eax
+       je      .Lrcls_retdouble
+       cmpl    $FFI_TYPE_LONGDOUBLE, %eax
+       je      .Lrcls_retldouble
+       cmpl    $FFI_TYPE_SINT64, %eax
+       je      .Lrcls_retllong
+.Lrcls_epilogue:
+       addl    $36, %esp
+       popl    %esi
+       popl    %ebp
+       ret
+.Lrcls_retint:
+       movl    -24(%ebp), %eax
+       jmp     .Lrcls_epilogue
+.Lrcls_retfloat:
+       flds    -24(%ebp)
+       jmp     .Lrcls_epilogue
+.Lrcls_retdouble:
+       fldl    -24(%ebp)
+       jmp     .Lrcls_epilogue
+.Lrcls_retldouble:
+       fldt    -24(%ebp)
+       jmp     .Lrcls_epilogue
+.Lrcls_retllong:
+       movl    -24(%ebp), %eax
+       movl    -20(%ebp), %edx
+       jmp     .Lrcls_epilogue
+.LFE3:
+#endif
+
+.section 
__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
+L_ffi_closure_SYSV_inner$stub:
+       .indirect_symbol _ffi_closure_SYSV_inner
+       hlt ; hlt ; hlt ; hlt ; hlt
+
+
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
+EH_frame1:
+       .set    L$set$0,LECIE1-LSCIE1
+       .long   L$set$0
+LSCIE1:
+       .long   0x0
+       .byte   0x1
+       .ascii "zR\0"
+       .byte   0x1
+       .byte   0x7c
+       .byte   0x8
+       .byte   0x1
+       .byte   0x10
+       .byte   0xc
+       .byte   0x5
+       .byte   0x4
+       .byte   0x88
+       .byte   0x1
+       .align 2
+LECIE1:
+.globl _ffi_call_SYSV.eh
+_ffi_call_SYSV.eh:
+LSFDE1:
+       .set    L$set$1,LEFDE1-LASFDE1
+       .long   L$set$1
+LASFDE1:
+       .long   LASFDE1-EH_frame1
+       .long   .LFB1-.
+       .set L$set$2,.LFE1-.LFB1
+       .long L$set$2
+       .byte   0x0
+       .byte   0x4
+       .set L$set$3,.LCFI0-.LFB1
+       .long L$set$3
+       .byte   0xe
+       .byte   0x8
+       .byte   0x84
+       .byte   0x2
+       .byte   0x4
+       .set L$set$4,.LCFI1-.LCFI0
+       .long L$set$4
+       .byte   0xd
+       .byte   0x4
+       .align 2
+LEFDE1:
+.globl _ffi_closure_SYSV.eh
+_ffi_closure_SYSV.eh:
+LSFDE2:
+       .set    L$set$5,LEFDE2-LASFDE2
+       .long   L$set$5
+LASFDE2:
+       .long   LASFDE2-EH_frame1
+       .long   .LFB2-.
+       .set L$set$6,.LFE2-.LFB2
+       .long L$set$6
+       .byte   0x0
+       .byte   0x4
+       .set L$set$7,.LCFI2-.LFB2
+       .long L$set$7
+       .byte   0xe
+       .byte   0x8
+       .byte   0x84
+       .byte   0x2
+       .byte   0x4
+       .set L$set$8,.LCFI3-.LCFI2
+       .long L$set$8
+       .byte   0xd
+       .byte   0x4
+       .align 2
+LEFDE2:
+
+#if !FFI_NO_RAW_API
+
+.globl _ffi_closure_raw_SYSV.eh
+_ffi_closure_raw_SYSV.eh:
+LSFDE3:
+       .set    L$set$10,LEFDE3-LASFDE3
+       .long   L$set$10
+LASFDE3:
+       .long   LASFDE3-EH_frame1
+       .long   .LFB3-.
+       .set L$set$11,.LFE3-.LFB3
+       .long L$set$11
+       .byte   0x0
+       .byte   0x4
+       .set L$set$12,.LCFI4-.LFB3
+       .long L$set$12
+       .byte   0xe
+       .byte   0x8
+       .byte   0x84
+       .byte   0x2
+       .byte   0x4
+       .set L$set$13,.LCFI5-.LCFI4
+       .long L$set$13
+       .byte   0xd
+       .byte   0x4
+       .byte   0x4
+       .set L$set$14,.LCFI6-.LCFI5
+       .long L$set$14
+       .byte   0x85
+       .byte   0x3
+       .align 2
+LEFDE3:
+
+#endif
+
+#endif /* ifndef __x86_64__ */

Index: libffi/src/x86/darwin64.S
===================================================================
RCS file: libffi/src/x86/darwin64.S
diff -N libffi/src/x86/darwin64.S
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libffi/src/x86/darwin64.S   30 Nov 2007 20:59:58 -0000      1.1
@@ -0,0 +1,415 @@
+/* -----------------------------------------------------------------------
+   darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc.
+   derived from unix64.S
+
+   x86-64 Foreign Function Interface for Darwin.
+
+   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.
+   ----------------------------------------------------------------------- */
+
+#ifdef __x86_64__
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+       .file "darwin64.S"
+.text
+
+/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
+                   void *raddr, void (*fnaddr)());
+
+   Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+   for this function.  This has been allocated by ffi_call.  We also
+   deallocate some of the stack that has been alloca'd.  */
+
+       .align  3
+       .globl  _ffi_call_unix64
+
+_ffi_call_unix64:
+LUW0:
+       movq    (%rsp), %r10            /* Load return address.  */
+       leaq    (%rdi, %rsi), %rax      /* Find local stack base.  */
+       movq    %rdx, (%rax)            /* Save flags.  */
+       movq    %rcx, 8(%rax)           /* Save raddr.  */
+       movq    %rbp, 16(%rax)          /* Save old frame pointer.  */
+       movq    %r10, 24(%rax)          /* Relocate return address.  */
+       movq    %rax, %rbp              /* Finalize local stack frame.  */
+LUW1:
+       movq    %rdi, %r10              /* Save a copy of the register area. */
+       movq    %r8, %r11               /* Save a copy of the target fn.  */
+       movl    %r9d, %eax              /* Set number of SSE registers.  */
+
+       /* Load up all argument registers.  */
+       movq    (%r10), %rdi
+       movq    8(%r10), %rsi
+       movq    16(%r10), %rdx
+       movq    24(%r10), %rcx
+       movq    32(%r10), %r8
+       movq    40(%r10), %r9
+       testl   %eax, %eax
+       jnz     Lload_sse
+Lret_from_load_sse:
+
+       /* Deallocate the reg arg area.  */
+       leaq    176(%r10), %rsp
+
+       /* Call the user function.  */
+       call    *%r11
+
+       /* Deallocate stack arg area; local stack frame in redzone.  */
+       leaq    24(%rbp), %rsp
+
+       movq    0(%rbp), %rcx           /* Reload flags.  */
+       movq    8(%rbp), %rdi           /* Reload raddr.  */
+       movq    16(%rbp), %rbp          /* Reload old frame pointer.  */
+LUW2:
+
+       /* The first byte of the flags contains the FFI_TYPE.  */
+       movzbl  %cl, %r10d
+       leaq    Lstore_table(%rip), %r11
+       movslq  (%r11, %r10, 4), %r10
+       addq    %r11, %r10
+       jmp     *%r10
+
+Lstore_table:
+       .long   Lst_void-Lstore_table           /* FFI_TYPE_VOID */
+       .long   Lst_sint32-Lstore_table         /* FFI_TYPE_INT */
+       .long   Lst_float-Lstore_table          /* FFI_TYPE_FLOAT */
+       .long   Lst_double-Lstore_table         /* FFI_TYPE_DOUBLE */
+       .long   Lst_ldouble-Lstore_table        /* FFI_TYPE_LONGDOUBLE */
+       .long   Lst_uint8-Lstore_table          /* FFI_TYPE_UINT8 */
+       .long   Lst_sint8-Lstore_table          /* FFI_TYPE_SINT8 */
+       .long   Lst_uint16-Lstore_table         /* FFI_TYPE_UINT16 */
+       .long   Lst_sint16-Lstore_table         /* FFI_TYPE_SINT16 */
+       .long   Lst_uint32-Lstore_table         /* FFI_TYPE_UINT32 */
+       .long   Lst_sint32-Lstore_table         /* FFI_TYPE_SINT32 */
+       .long   Lst_int64-Lstore_table          /* FFI_TYPE_UINT64 */
+       .long   Lst_int64-Lstore_table          /* FFI_TYPE_SINT64 */
+       .long   Lst_struct-Lstore_table         /* FFI_TYPE_STRUCT */
+       .long   Lst_int64-Lstore_table          /* FFI_TYPE_POINTER */
+
+       .text
+       .align  3
+Lst_void:
+       ret
+       .align  3
+Lst_uint8:
+       movzbq  %al, %rax
+       movq    %rax, (%rdi)
+       ret
+       .align  3
+Lst_sint8:
+       movsbq  %al, %rax
+       movq    %rax, (%rdi)
+       ret
+       .align  3
+Lst_uint16:
+       movzwq  %ax, %rax
+       movq    %rax, (%rdi)
+       .align  3
+Lst_sint16:
+       movswq  %ax, %rax
+       movq    %rax, (%rdi)
+       ret
+       .align  3
+Lst_uint32:
+       movl    %eax, %eax
+       movq    %rax, (%rdi)
+       .align  3
+Lst_sint32:
+       cltq
+       movq    %rax, (%rdi)
+       ret
+       .align  3
+Lst_int64:
+       movq    %rax, (%rdi)
+       ret
+       .align  3
+Lst_float:
+       movss   %xmm0, (%rdi)
+       ret
+       .align  3
+Lst_double:
+       movsd   %xmm0, (%rdi)
+       ret
+Lst_ldouble:
+       fstpt   (%rdi)
+       ret
+       .align  3
+Lst_struct:
+       leaq    -20(%rsp), %rsi         /* Scratch area in redzone.  */
+
+       /* We have to locate the values now, and since we don't want to
+          write too much data into the user's return value, we spill the
+          value to a 16 byte scratch area first.  Bits 8, 9, and 10
+          control where the values are located.  Only one of the three
+          bits will be set; see ffi_prep_cif_machdep for the pattern.  */
+       movd    %xmm0, %r10
+       movd    %xmm1, %r11
+       testl   $0x100, %ecx
+       cmovnz  %rax, %rdx
+       cmovnz  %r10, %rax
+       testl   $0x200, %ecx
+       cmovnz  %r10, %rdx
+       testl   $0x400, %ecx
+       cmovnz  %r10, %rax
+       cmovnz  %r11, %rdx
+       movq    %rax, (%rsi)
+       movq    %rdx, 8(%rsi)
+
+       /* Bits 12-31 contain the true size of the structure.  Copy from
+          the scratch area to the true destination.  */
+       shrl    $12, %ecx
+       rep movsb
+       ret
+
+       /* Many times we can avoid loading any SSE registers at all.
+          It's not worth an indirect jump to load the exact set of
+          SSE registers needed; zero or all is a good compromise.  */
+       .align  3
+LUW3:
+Lload_sse:
+       movdqa  48(%r10), %xmm0
+       movdqa  64(%r10), %xmm1
+       movdqa  80(%r10), %xmm2
+       movdqa  96(%r10), %xmm3
+       movdqa  112(%r10), %xmm4
+       movdqa  128(%r10), %xmm5
+       movdqa  144(%r10), %xmm6
+       movdqa  160(%r10), %xmm7
+       jmp     Lret_from_load_sse
+
+LUW4:
+       .align  3
+       .globl  _ffi_closure_unix64
+
+_ffi_closure_unix64:
+LUW5:
+       /* The carry flag is set by the trampoline iff SSE registers
+          are used.  Don't clobber it before the branch instruction.  */
+       leaq    -200(%rsp), %rsp
+LUW6:
+       movq    %rdi, (%rsp)
+       movq    %rsi, 8(%rsp)
+       movq    %rdx, 16(%rsp)
+       movq    %rcx, 24(%rsp)
+       movq    %r8, 32(%rsp)
+       movq    %r9, 40(%rsp)
+       jc      Lsave_sse
+Lret_from_save_sse:
+
+       movq    %r10, %rdi
+       leaq    176(%rsp), %rsi
+       movq    %rsp, %rdx
+       leaq    208(%rsp), %rcx
+       call    _ffi_closure_unix64_inner
+
+       /* Deallocate stack frame early; return value is now in redzone.  */
+       addq    $200, %rsp
+LUW7:
+
+       /* The first byte of the return value contains the FFI_TYPE.  */
+       movzbl  %al, %r10d
+       leaq    Lload_table(%rip), %r11
+       movslq  (%r11, %r10, 4), %r10
+       addq    %r11, %r10
+       jmp     *%r10
+
+Lload_table:
+       .long   Lld_void-Lload_table            /* FFI_TYPE_VOID */
+       .long   Lld_int32-Lload_table           /* FFI_TYPE_INT */
+       .long   Lld_float-Lload_table           /* FFI_TYPE_FLOAT */
+       .long   Lld_double-Lload_table          /* FFI_TYPE_DOUBLE */
+       .long   Lld_ldouble-Lload_table         /* FFI_TYPE_LONGDOUBLE */
+       .long   Lld_int8-Lload_table            /* FFI_TYPE_UINT8 */
+       .long   Lld_int8-Lload_table            /* FFI_TYPE_SINT8 */
+       .long   Lld_int16-Lload_table           /* FFI_TYPE_UINT16 */
+       .long   Lld_int16-Lload_table           /* FFI_TYPE_SINT16 */
+       .long   Lld_int32-Lload_table           /* FFI_TYPE_UINT32 */
+       .long   Lld_int32-Lload_table           /* FFI_TYPE_SINT32 */
+       .long   Lld_int64-Lload_table           /* FFI_TYPE_UINT64 */
+       .long   Lld_int64-Lload_table           /* FFI_TYPE_SINT64 */
+       .long   Lld_struct-Lload_table          /* FFI_TYPE_STRUCT */
+       .long   Lld_int64-Lload_table           /* FFI_TYPE_POINTER */
+
+       .text
+       .align  3
+Lld_void:
+       ret
+       .align  3
+Lld_int8:
+       movzbl  -24(%rsp), %eax
+       ret
+       .align  3
+Lld_int16:
+       movzwl  -24(%rsp), %eax
+       ret
+       .align  3
+Lld_int32:
+       movl    -24(%rsp), %eax
+       ret
+       .align  3
+Lld_int64:
+       movq    -24(%rsp), %rax
+       ret
+       .align  3
+Lld_float:
+       movss   -24(%rsp), %xmm0
+       ret
+       .align  3
+Lld_double:
+       movsd   -24(%rsp), %xmm0
+       ret
+       .align  3
+Lld_ldouble:
+       fldt    -24(%rsp)
+       ret
+       .align  3
+Lld_struct:
+       /* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
+          %rax/%xmm0, %xmm0/%xmm1.  We collapse two by always loading
+          both rdx and xmm1 with the second word.  For the remaining,
+          bit 8 set means xmm0 gets the second word, and bit 9 means
+          that rax gets the second word.  */
+       movq    -24(%rsp), %rcx
+       movq    -16(%rsp), %rdx
+       movq    -16(%rsp), %xmm1
+       testl   $0x100, %eax
+       cmovnz  %rdx, %rcx
+       movd    %rcx, %xmm0
+       testl   $0x200, %eax
+       movq    -24(%rsp), %rax
+       cmovnz  %rdx, %rax
+       ret
+
+       /* See the comment above Lload_sse; the same logic applies here.  */
+       .align  3
+LUW8:
+Lsave_sse:
+       movdqa  %xmm0, 48(%rsp)
+       movdqa  %xmm1, 64(%rsp)
+       movdqa  %xmm2, 80(%rsp)
+       movdqa  %xmm3, 96(%rsp)
+       movdqa  %xmm4, 112(%rsp)
+       movdqa  %xmm5, 128(%rsp)
+       movdqa  %xmm6, 144(%rsp)
+       movdqa  %xmm7, 160(%rsp)
+       jmp     Lret_from_save_sse
+
+LUW9:
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
+EH_frame1:
+       .set    L$set$0,LECIE1-LSCIE1           /* CIE Length */
+       .long   L$set$0
+LSCIE1:
+       .long   0x0             /* CIE Identifier Tag */
+       .byte   0x1             /* CIE Version */
+       .ascii  "zR\0"          /* CIE Augmentation */
+       .byte   0x1             /* uleb128 0x1; CIE Code Alignment Factor */
+       .byte   0x78            /* sleb128 -8; CIE Data Alignment Factor */
+       .byte   0x10            /* CIE RA Column */
+       .byte   0x1             /* uleb128 0x1; Augmentation size */
+       .byte   0x10            /* FDE Encoding (pcrel sdata4) */
+       .byte   0xc             /* DW_CFA_def_cfa, %rsp offset 8 */
+       .byte   0x7             /* uleb128 0x7 */
+       .byte   0x8             /* uleb128 0x8 */
+       .byte   0x90            /* DW_CFA_offset, column 0x10 */
+       .byte   0x1
+       .align  3
+LECIE1:
+       .globl _ffi_call_unix64.eh
+_ffi_call_unix64.eh:
+LSFDE1:
+       .set    L$set$1,LEFDE1-LASFDE1  /* FDE Length */
+       .long   L$set$1
+LASFDE1:
+       .long   LASFDE1-EH_frame1       /* FDE CIE offset */
+       .quad   LUW0-.                  /* FDE initial location */
+       .set    L$set$2,LUW4-LUW0       /* FDE address range */
+       .quad   L$set$2
+       .byte   0x0                     /* Augmentation size */
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$3,LUW1-LUW0
+       .long   L$set$3
+
+       /* New stack frame based off rbp.  This is a itty bit of unwind
+          trickery in that the CFA *has* changed.  There is no easy way
+          to describe it correctly on entry to the function.  Fortunately,
+          it doesn't matter too much since at all points we can correctly
+          unwind back to ffi_call.  Note that the location to which we
+          moved the return address is (the new) CFA-8, so from the
+          perspective of the unwind info, it hasn't moved.  */
+       .byte   0xc                     /* DW_CFA_def_cfa, %rbp offset 32 */
+       .byte   0x6
+       .byte   0x20
+       .byte   0x80+6                  /* DW_CFA_offset, %rbp offset 2*-8 */
+       .byte   0x2
+       .byte   0xa                     /* DW_CFA_remember_state */
+
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$4,LUW2-LUW1
+       .long   L$set$4
+       .byte   0xc                     /* DW_CFA_def_cfa, %rsp offset 8 */
+       .byte   0x7
+       .byte   0x8
+       .byte   0xc0+6                  /* DW_CFA_restore, %rbp */
+
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$5,LUW3-LUW2
+       .long   L$set$5
+       .byte   0xb                     /* DW_CFA_restore_state */
+
+       .align  3
+LEFDE1:
+       .globl _ffi_closure_unix64.eh
+_ffi_closure_unix64.eh:
+LSFDE3:
+       .set    L$set$6,LEFDE3-LASFDE3  /* FDE Length */
+       .long   L$set$6
+LASFDE3:
+       .long   LASFDE3-EH_frame1       /* FDE CIE offset */
+       .quad   LUW5-.                  /* FDE initial location */
+       .set    L$set$7,LUW9-LUW5       /* FDE address range */
+       .quad   L$set$7
+       .byte   0x0                     /* Augmentation size */
+
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$8,LUW6-LUW5
+       .long   L$set$8
+       .byte   0xe                     /* DW_CFA_def_cfa_offset */
+       .byte   208,1                   /* uleb128 208 */
+       .byte   0xa                     /* DW_CFA_remember_state */
+
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$9,LUW7-LUW6
+       .long   L$set$9
+       .byte   0xe                     /* DW_CFA_def_cfa_offset */
+       .byte   0x8
+
+       .byte   0x4                     /* DW_CFA_advance_loc4 */
+       .set    L$set$10,LUW8-LUW7
+       .long   L$set$10
+       .byte   0xb                     /* DW_CFA_restore_state */
+
+       .align  3
+LEFDE3:
+       .subsections_via_symbols
+
+#endif /* __x86_64__ */

Index: libffi/src/ffitest.c
===================================================================
RCS file: libffi/src/ffitest.c
diff -N libffi/src/ffitest.c
--- libffi/src/ffitest.c        30 Jul 2005 19:00:13 -0000      1.3
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,1314 +0,0 @@
-/* -----------------------------------------------------------------------
-   ffitest.c - Copyright (c) 1996, 1997, 1998, 2002, 2003  Red Hat, Inc.
-
-   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 CYGNUS SOLUTIONS 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.
-   ----------------------------------------------------------------------- */
-
-#include <ffi.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-
-/* This is lame. Long double support is barely there under SunOS 4.x  */
-#if defined(SPARC) && (SIZEOF_LONG_DOUBLE != 16)
-#define BROKEN_LONG_DOUBLE
-#endif
-
-#define CHECK(x) !(x) ? fail(__FILE__, __LINE__) : 0 
-
-static int fail(char *file, int line)
-{
-  fprintf(stderr, "Test failure: %s line %d\n", file, line);
-  exit(EXIT_FAILURE);
-  /address@hidden@*/
-  return 0;
-}
-
-#define MAX_ARGS 256
-
-static size_t my_strlen(char *s)
-{
-  return (strlen(s));
-}
-
-#ifdef X86_WIN32
-static size_t __attribute__((stdcall)) my_stdcall_strlen(char *s)
-{
-  return (strlen(s));
-}
-#endif /* X86_WIN32 */
-
-static int promotion(signed char sc, signed short ss, 
-                    unsigned char uc, unsigned short us)
-{
-  int r = (int) sc + (int) ss + (int) uc + (int) us;
-
-  return r;
-}
-
-static signed char return_sc(signed char sc)
-{
-  return sc;
-}
-
-static unsigned char return_uc(unsigned char uc)
-{
-  return uc;
-}
-
-static long long return_ll(long long ll)
-{
-  return ll;
-}
-
-static int floating(int a, float b, double c, long double d, int e)
-{
-  int i;
-
-#if 0
-  /* This is ifdef'd out for now. long double support under SunOS/gcc
-     is pretty much non-existent.  You'll get the odd bus error in library
-     routines like printf().  */
-  printf("%d %f %f %Lf %d\n", a, (double)b, c, d, e);
-#endif
-
-  i = (int) ((float)a/b + ((float)c/(float)d));
-
-  return i;
-}
-
-static float many(float f1,
-                 float f2,
-                 float f3,
-                 float f4,
-                 float f5,
-                 float f6,
-                 float f7,
-                 float f8,
-                 float f9,
-                 float f10,
-                 float f11,
-                 float f12,
-                 float f13)
-{
-#if 0
-  printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
-        (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, 
-        (double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
-        (double) f11, (double) f12, (double) f13);
-#endif
-
-  return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
-}
-
-#ifdef X86_WIN32
-static float __attribute__((stdcall)) stdcall_many(float f1,
-                                                  float f2,
-                                                  float f3,
-                                                  float f4,
-                                                  float f5,
-                                                  float f6,
-                                                  float f7,
-                                                  float f8,
-                                                  float f9,
-                                                  float f10,
-                                                  float f11,
-                                                  float f12,
-                                                  float f13)
-{
-  return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
-}
-#endif /* X86_WIN32 */
-
-static double dblit(float f)
-{
-  return f/3.0;
-}
-
-static long double ldblit(float f)
-{
-  return (long double) (((long double) f)/ (long double) 3.0);
-}
-
-typedef struct
-{
-  unsigned char uc;
-  double d;
-  unsigned int ui;
-} test_structure_1;
-
-typedef struct
-{
-  double d1;
-  double d2;
-} test_structure_2;
-
-typedef struct
-{
-  int si;
-} test_structure_3;
-
-typedef struct
-{
-  unsigned ui1;
-  unsigned ui2;
-  unsigned ui3;
-} test_structure_4;
-
-typedef struct
-{
-  char c1;
-  char c2;
-} test_structure_5;
-
-typedef struct
-{
-  float f;
-  double d;
-} test_structure_6;
-
-typedef struct
-{
-  float f1;
-  float f2;
-  double d;
-} test_structure_7;
-
-typedef struct
-{
-  float f1;
-  float f2;
-  float f3;
-  float f4;
-} test_structure_8;
-
-typedef struct
-{
-  float f;
-  int i;
-} test_structure_9;
-
-static test_structure_1 struct1(test_structure_1 ts)
-{
-  /address@hidden@*/
-  ts.uc++;
-  /address@hidden@*/
-  ts.d--;
-  ts.ui++;
-
-  return ts;
-}
-
-static test_structure_2 struct2(test_structure_2 ts)
-{
-  ts.d1--;
-  ts.d2--;
-
-  return ts;
-}
-
-static test_structure_3 struct3(test_structure_3 ts)
-{
-  ts.si = -(ts.si*2);
-
-  return ts;
-}
-
-static test_structure_4 struct4(test_structure_4 ts)
-{
-  ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3;
-
-  return ts;
-}
-
-static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
-{
-  ts1.c1 += ts2.c1;
-  ts1.c2 -= ts2.c2;
-
-  return ts1;
-}
-
-static test_structure_6 struct6 (test_structure_6 ts)
-{
-  ts.f += 1;
-  ts.d += 1;
-
-  return ts;
-}
-
-static test_structure_7 struct7 (test_structure_7 ts)
-{
-  ts.f1 += 1;
-  ts.f2 += 1;
-  ts.d += 1;
-
-  return ts;
-}
-
-static test_structure_8 struct8 (test_structure_8 ts)
-{
-  ts.f1 += 1;
-  ts.f2 += 1;
-  ts.f3 += 1;
-  ts.f4 += 1;
-
-  return ts;
-}
-
-static test_structure_9 struct9 (test_structure_9 ts)
-{
-  ts.f += 1;
-  ts.i += 1;
-
-  return ts;
-}
-
-/* Take an int and a float argument, together with int userdata, and   */
-/* return the sum.                                                     */
-#if FFI_CLOSURES
-static void
-closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
-{
-  *(ffi_arg*)resp =
-    (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) +
-    (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] +
-    (int)(*(signed short *)args[4]) +
-    (int)(*(unsigned long long *)args[5]) +
-    (int)*(int *)args[6] + (int)(*(int *)args[7]) +
-    (int)(*(double *)args[8]) + (int)*(int *)args[9] +
-    (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
-    (int)*(int *)args[12] + (int)(*(int *)args[13]) +
-    (int)(*(int *)args[14]) +  *(int *)args[15] + (int)(long)userdata;
-
-       printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
-              (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]), 
-              (int)(*(unsigned long long *)args[2]),
-              (int)*(int *)args[3], (int)(*(signed short *)args[4]), 
-              (int)(*(unsigned long long *)args[5]),
-              (int)*(int *)args[6], (int)(*(int *)args[7]), 
-              (int)(*(double *)args[8]), (int)*(int *)args[9],
-              (int)(*(int *)args[10]), (int)(*(float *)args[11]),
-              (int)*(int *)args[12], (int)(*(int *)args[13]), 
-              (int)(*(int *)args[14]),*(int *)args[15],
-              (int)(long)userdata, (int)*(ffi_arg *)resp);
-}
-
-typedef int (*closure_test_type)(unsigned long long, int, unsigned long long, 
-                                int, signed short, unsigned long long, int, 
-                                int, double, int, int, float, int, int, 
-                                int, int);
-
-static void closure_test_fn1(ffi_cif* cif,void* resp,void** args, 
-                            void* userdata)
- {
-    *(ffi_arg*)resp =
-      (int)*(float *)args[0] +(int)(*(float *)args[1]) + 
-      (int)(*(float *)args[2]) + (int)*(float *)args[3] +
-      (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) +
-      (int)*(float *)args[6] + (int)(*(int *)args[7]) + 
-      (int)(*(double*)args[8]) + (int)*(int *)args[9] + 
-      (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + 
-      (int)*(int *)args[12] + (int)(*(int *)args[13]) + 
-      (int)(*(int *)args[14]) + *(int *)args[15] + (int)(long)userdata;
-
-    printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
-          (int)*(float *)args[0], (int)(*(float *)args[1]), 
-          (int)(*(float *)args[2]), (int)*(float *)args[3], 
-          (int)(*(signed short *)args[4]), (int)(*(float *)args[5]),
-          (int)*(float *)args[6], (int)(*(int *)args[7]),
-          (int)(*(double *)args[8]), (int)*(int *)args[9],
-          (int)(*(int *)args[10]), (int)(*(float *)args[11]),
-          (int)*(int *)args[12], (int)(*(int *)args[13]),
-          (int)(*(int *)args[14]), *(int *)args[15],
-          (int)(long)userdata, (int)*(ffi_arg *)resp);
-}
-
-typedef int (*closure_test_type1)(float, float, float, float, signed short, 
-                                 float, float, int, double, int, int, float,
-                                 int, int, int, int);
-
-static void closure_test_fn2(ffi_cif* cif,void* resp,void** args, 
-                            void* userdata)
- {
-    *(ffi_arg*)resp =
-      (int)*(double *)args[0] +(int)(*(double *)args[1]) + 
-      (int)(*(double *)args[2]) + (int)*(double *)args[3] +
-      (int)(*(signed short *)args[4]) + (int)(*(double *)args[5]) +
-      (int)*(double *)args[6] + (int)(*(int *)args[7]) + 
-      (int)(*(double *)args[8]) + (int)*(int *)args[9] +
-      (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + 
-      (int)*(int *)args[12] + (int)(*(float *)args[13]) +
-      (int)(*(int *)args[14]) + *(int *)args[15] + (int)(long)userdata;
-
-    printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
-          (int)*(double *)args[0], (int)(*(double *)args[1]), 
-          (int)(*(double *)args[2]), (int)*(double *)args[3], 
-          (int)(*(signed short *)args[4]), (int)(*(double *)args[5]),
-          (int)*(double *)args[6], (int)(*(int *)args[7]), 
-          (int)(*(double*)args[8]), (int)*(int *)args[9], 
-          (int)(*(int *)args[10]), (int)(*(float *)args[11]),
-          (int)*(int *)args[12], (int)(*(float *)args[13]), 
-          (int)(*(int *)args[14]), *(int *)args[15], (int)(long)userdata, 
-          (int)*(ffi_arg *)resp);
- }
-
-typedef int (*closure_test_type2)(double, double, double, double, signed short,
-                                 double, double, int, double, int, int, float,
-                                 int, float, int, int);
-
-static void closure_test_fn3(ffi_cif* cif,void* resp,void** args,
-                            void* userdata)
- {
-    *(ffi_arg*)resp =
-      (int)*(float *)args[0] +(int)(*(float *)args[1]) + 
-      (int)(*(float *)args[2]) + (int)*(float *)args[3] +
-      (int)(*(float *)args[4]) + (int)(*(float *)args[5]) +
-      (int)*(float *)args[6] + (int)(*(float *)args[7]) + 
-      (int)(*(double *)args[8]) + (int)*(int *)args[9] +
-      (int)(*(float *)args[10]) + (int)(*(float *)args[11]) + 
-      (int)*(int *)args[12] + (int)(*(float *)args[13]) +
-      (int)(*(float *)args[14]) +  *(int *)args[15] + (int)(long)userdata;
-
-    printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
-          (int)*(float *)args[0], (int)(*(float *)args[1]), 
-          (int)(*(float *)args[2]), (int)*(float *)args[3], 
-          (int)(*(float *)args[4]), (int)(*(float *)args[5]),
-          (int)*(float *)args[6], (int)(*(float *)args[7]), 
-          (int)(*(double *)args[8]), (int)*(int *)args[9], 
-          (int)(*(float *)args[10]), (int)(*(float *)args[11]),
-          (int)*(int *)args[12], (int)(*(float *)args[13]), 
-          (int)(*(float *)args[14]), *(int *)args[15], (int)(long)userdata,
-          (int)*(ffi_arg *)resp);
- }
-
-typedef int (*closure_test_type3)(float, float, float, float, float, float,
-                                 float, float, double, int, float, float, int,
-                                 float, float, int);
-#endif
-
-int main(/address@hidden@*/ int argc, /address@hidden@*/ char *argv[])
-{
-  ffi_cif cif;
-  ffi_type *args[MAX_ARGS];
-  void *values[MAX_ARGS];
-  char *s;
-  signed char sc;
-  unsigned char uc;
-  signed short ss;
-  unsigned short us;
-  unsigned long ul;
-  long long ll;
-  float f;
-  double d;
-  long double ld;
-  signed int si1;
-  signed int si2;
-
-  ffi_arg rint;
-  long long rlonglong;
-
-# if FFI_CLOSURES
-  /* The closure must not be an automatic variable on
-     platforms (Solaris) that forbid stack execution by default. */
-  static ffi_closure cl;
-  ffi_closure *pcl = &cl;
-#endif
-
-  ffi_type * cl_arg_types[17];
-
-  ffi_type ts1_type;
-  ffi_type ts2_type;
-  ffi_type ts3_type;
-  ffi_type ts4_type;  
-  ffi_type ts5_type;
-  ffi_type ts6_type;
-  ffi_type ts7_type;
-  ffi_type ts8_type;
-  ffi_type ts9_type;
-  ffi_type *ts1_type_elements[4];
-  ffi_type *ts2_type_elements[3];
-  ffi_type *ts3_type_elements[2];
-  ffi_type *ts4_type_elements[4];
-  ffi_type *ts5_type_elements[3];
-  ffi_type *ts6_type_elements[3];
-  ffi_type *ts7_type_elements[4];
-  ffi_type *ts8_type_elements[5];
-  ffi_type *ts9_type_elements[3];
-
-  ts1_type.size = 0;
-  ts1_type.alignment = 0;
-  ts1_type.type = FFI_TYPE_STRUCT;
-
-  ts2_type.size = 0;
-  ts2_type.alignment = 0;
-  ts2_type.type = FFI_TYPE_STRUCT;
-
-  ts3_type.size = 0;
-  ts3_type.alignment = 0;
-  ts3_type.type = FFI_TYPE_STRUCT;
-
-  ts4_type.size = 0;
-  ts4_type.alignment = 0;
-  ts4_type.type = FFI_TYPE_STRUCT;
-
-  ts5_type.size = 0;
-  ts5_type.alignment = 0;
-  ts5_type.type = FFI_TYPE_STRUCT;
-
-  ts6_type.size = 0;
-  ts6_type.alignment = 0;
-  ts6_type.type = FFI_TYPE_STRUCT;
-
-  ts7_type.size = 0;
-  ts7_type.alignment = 0;
-  ts7_type.type = FFI_TYPE_STRUCT;
-
-  ts8_type.size = 0;
-  ts8_type.alignment = 0;
-  ts8_type.type = FFI_TYPE_STRUCT;
-
-  ts9_type.size = 0;
-  ts9_type.alignment = 0;
-  ts9_type.type = FFI_TYPE_STRUCT;
-
-  /address@hidden@*/
-  ts1_type.elements = ts1_type_elements;
-  ts2_type.elements = ts2_type_elements;
-  ts3_type.elements = ts3_type_elements;
-  ts4_type.elements = ts4_type_elements;
-  ts5_type.elements = ts5_type_elements;
-  ts6_type.elements = ts6_type_elements;
-  ts7_type.elements = ts7_type_elements;
-  ts8_type.elements = ts8_type_elements;
-  ts9_type.elements = ts9_type_elements;
-  /address@hidden@*/
-  
-  ts1_type_elements[0] = &ffi_type_uchar;
-  ts1_type_elements[1] = &ffi_type_double;
-  ts1_type_elements[2] = &ffi_type_uint;
-  ts1_type_elements[3] = NULL;
-  
-  ts2_type_elements[0] = &ffi_type_double;
-  ts2_type_elements[1] = &ffi_type_double;
-  ts2_type_elements[2] = NULL;
-
-  ts3_type_elements[0] = &ffi_type_sint;
-  ts3_type_elements[1] = NULL;
-
-  ts4_type_elements[0] = &ffi_type_uint;
-  ts4_type_elements[1] = &ffi_type_uint;
-  ts4_type_elements[2] = &ffi_type_uint;
-  ts4_type_elements[3] = NULL;
-
-  ts5_type_elements[0] = &ffi_type_schar;
-  ts5_type_elements[1] = &ffi_type_schar;
-  ts5_type_elements[2] = NULL;
-
-  ts6_type_elements[0] = &ffi_type_float;
-  ts6_type_elements[1] = &ffi_type_double;
-  ts6_type_elements[2] = NULL;
-
-  ts7_type_elements[0] = &ffi_type_float;
-  ts7_type_elements[1] = &ffi_type_float;
-  ts7_type_elements[2] = &ffi_type_double;
-  ts7_type_elements[3] = NULL;
-
-  ts8_type_elements[0] = &ffi_type_float;
-  ts8_type_elements[1] = &ffi_type_float;
-  ts8_type_elements[2] = &ffi_type_float;
-  ts8_type_elements[3] = &ffi_type_float;
-  ts8_type_elements[4] = NULL;
-
-  ts9_type_elements[0] = &ffi_type_float;
-  ts9_type_elements[1] = &ffi_type_sint;
-  ts9_type_elements[2] = NULL;
-
-  ul = 0;
-
-  /* return value tests */
-  {
-#if defined(MIPS) /* || defined(ARM) */
-    puts ("long long tests not run. This is a known bug on this 
architecture.");
-#else
-    args[0] = &ffi_type_sint64;
-    values[0] = &ll;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_sint64, args) == FFI_OK);
-
-    for (ll = 0LL; ll < 100LL; ll++)
-      {
-       ul++;
-       ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
-       CHECK(rlonglong == ll);
-      }
-
-    for (ll = 55555555555000LL; ll < 55555555555100LL; ll++)
-      {
-       ul++;
-       ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
-       CHECK(rlonglong == ll);
-      }
-#endif
-
-    args[0] = &ffi_type_schar;
-    values[0] = &sc;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_schar, args) == FFI_OK);
-
-    for (sc = (signed char) -127; 
-        sc < (signed char) 127; /address@hidden@*/ sc++ /address@hidden@*/)
-      {
-       ul++;
-       ffi_call(&cif, FFI_FN(return_sc), &rint, values);
-       CHECK(rint == (ffi_arg) sc);
-      }
-
-    args[0] = &ffi_type_uchar;
-    values[0] = &uc;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_uchar, args) == FFI_OK);
-
-    for (uc = (unsigned char) '\x00'; 
-        uc < (unsigned char) '\xff'; /address@hidden@*/ uc++ 
/address@hidden@*/)
-      {
-       ul++;
-       ffi_call(&cif, FFI_FN(return_uc), &rint, values);
-       CHECK(rint == (signed int) uc);
-      }
-
-    printf("%lu return value tests run\n", ul);
-  }
-
-#ifdef BROKEN_LONG_DOUBLE
-  printf ("This architecture has broken `long double' support. No floating 
point\ntests have been run.\n");
-#else
-  /* float arg tests */
-  {
-    args[0] = &ffi_type_float;
-    values[0] = &f;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_longdouble, args) == FFI_OK);
-
-    f = 3.14159;
-
-#if 0
-  /* This is ifdef'd out for now. long double support under SunOS/gcc
-     is pretty much non-existent.  You'll get the odd bus error in library
-     routines like printf().  */
-    printf ("%Lf\n", ldblit(f));
-#endif
-    ld = 666;
-    ffi_call(&cif, FFI_FN(ldblit), &ld, values);
-
-#if 0
-  /* This is ifdef'd out for now. long double support under SunOS/gcc
-     is pretty much non-existent.  You'll get the odd bus error in library
-     routines like printf().  */
-    printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), 
LDBL_EPSILON);
-#endif
-
-    /* These are not always the same!! Check for a reasonable delta */
-    /address@hidden@*/
-    if (ld - ldblit(f) < LDBL_EPSILON)
-    /address@hidden@*/
-       puts("long double return value tests ok!");
-    else
-        CHECK(0);
-  }
-
-  /* float arg tests */
-  {
-    args[0] = &ffi_type_sint;
-    values[0] = &si1;
-    args[1] = &ffi_type_float;
-    values[1] = &f;
-    args[2] = &ffi_type_double;
-    values[2] = &d;
-    args[3] = &ffi_type_longdouble;
-    values[3] = &ld;
-    args[4] = &ffi_type_sint;
-    values[4] = &si2;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5,
-                      &ffi_type_sint, args) == FFI_OK);
-
-    si1 = 6;
-    f = 3.14159;
-    d = (double)1.0/(double)3.0;
-    ld = 2.71828182846L;
-    si2 = 10;
-
-    floating (si1, f, d, ld, si2);
-
-    ffi_call(&cif, FFI_FN(floating), &rint, values);
-
-    printf ("%d vs %d\n", (int)rint, floating (si1, f, d, ld, si2));
-
-    CHECK(rint == floating(si1, f, d, ld, si2));
-
-    printf("float arg tests ok!\n");
-  }
-#endif
-
-  /* strlen tests */
-  {
-    args[0] = &ffi_type_pointer;
-    values[0] = (void*) &s;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_sint, args) == FFI_OK);
-
-    s = "a";
-    ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
-    CHECK(rint == 1);
-
-    s = "1234567";
-    ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
-    CHECK(rint == 7);
-
-    s = "1234567890123456789012345";
-    ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
-    CHECK(rint == 25);
-
-    printf("strlen tests passed\n");
-  }
-
-  /* float arg tests */
-  {
-    args[0] = &ffi_type_float;
-    values[0] = &f;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ffi_type_double, args) == FFI_OK);
-
-    f = 3.14159;
-
-    ffi_call(&cif, FFI_FN(dblit), &d, values);
-
-    /* These are not always the same!! Check for a reasonable delta */
-    /address@hidden@*/
-    CHECK(d - dblit(f) < DBL_EPSILON);
-    /address@hidden@*/
-
-    printf("double return value tests ok!\n");
-  }
-
-  /* many arg tests */
-  {
-    float ff;
-    float fa[13];
-    
-    for (ul = 0; ul < 13; ul++)
-      {
-       args[ul] = &ffi_type_float;
-       values[ul] = &fa[ul];
-       fa[ul] = (float) ul;
-      }
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, 
-                      &ffi_type_float, args) == FFI_OK);
-
-    /address@hidden@*/
-    ff = many (fa[0], fa[1],
-              fa[2], fa[3],
-              fa[4], fa[5],
-              fa[6], fa[7],
-              fa[8], fa[9],
-              fa[10],fa[11],fa[12]);
-    /address@hidden@*/
-
-    ffi_call(&cif, FFI_FN(many), &f, values);
-
-    /address@hidden@*/
-    if (f - ff < FLT_EPSILON)
-    /address@hidden@*/
-       printf("many arg tests ok!\n");
-    else
-#ifdef POWERPC
-       printf("many arg tests failed!  This is a gcc bug.\n");
-#else
-        CHECK(0);
-#endif
-  }
-
-  /* promotion tests */
-  {
-    args[0] = &ffi_type_schar;
-    args[1] = &ffi_type_sshort;
-    args[2] = &ffi_type_uchar;
-    args[3] = &ffi_type_ushort;
-    values[0] = &sc;
-    values[1] = &ss;
-    values[2] = &uc;
-    values[3] = &us;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, 
-                      &ffi_type_sint, args) == FFI_OK);
-
-    us = 0;
-    ul = 0;
-
-    for (sc = (signed char) -127; 
-        sc <= (signed char) 120; /address@hidden@*/ sc += 1 /address@hidden@*/)
-      for (ss = -30000; ss <= 30000; ss += 10000)
-       for (uc = (unsigned char) 0; 
-            uc <= (unsigned char) 200; /address@hidden@*/ uc += 20 
/address@hidden@*/)
-         for (us = 0; us <= 60000; us += 10000)
-           {
-             ul++;
-             ffi_call(&cif, FFI_FN(promotion), &rint, values);
-             CHECK((int)rint == (signed char) sc + (signed short) ss +
-                   (unsigned char) uc + (unsigned short) us);
-           }
-    printf("%lu promotion tests run\n", ul);
-  }
-
-#ifndef X86_WIN32 /* Structures dont work on Win32 */
-
-  /* struct tests */
-  {
-    test_structure_1 ts1_arg;
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_1 *ts1_result = 
-      (test_structure_1 *) malloc (sizeof(test_structure_1));
-
-    args[0] = &ts1_type;
-    values[0] = &ts1_arg;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ts1_type, args) == FFI_OK);
-
-    ts1_arg.uc = '\x01';
-    ts1_arg.d = 3.14159;
-    ts1_arg.ui = 555;
-
-    ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
-
-    CHECK(ts1_result->ui == 556);
-    CHECK(ts1_result->d == 3.14159 - 1);
-
-    puts ("structure test 1 ok!\n");
-
-    free (ts1_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_2 ts2_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_2 *ts2_result = 
-      (test_structure_2 *) malloc (sizeof(test_structure_2));
-
-    args[0] = &ts2_type;
-    values[0] = &ts2_arg;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK);
-
-    ts2_arg.d1 = 5.55;
-    ts2_arg.d2 = 6.66;
-
-    printf ("%g\n", ts2_arg.d1);
-    printf ("%g\n", ts2_arg.d2);
-
-    ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
-
-    printf ("%g\n", ts2_result->d1);
-    printf ("%g\n", ts2_result->d2);
-    
-    CHECK(ts2_result->d1 == 5.55 - 1);
-    CHECK(ts2_result->d2 == 6.66 - 1);
-
-    printf("structure test 2 ok!\n");
-
-    free (ts2_result);
-  }
-
-  /* struct tests */
-  {
-    int compare_value;
-    test_structure_3 ts3_arg;
-    test_structure_3 *ts3_result = 
-      (test_structure_3 *) malloc (sizeof(test_structure_3));
-
-    args[0] = &ts3_type;
-    values[0] = &ts3_arg;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
-                      &ts3_type, args) == FFI_OK);
-
-    ts3_arg.si = -123;
-    compare_value = ts3_arg.si;
-
-    ffi_call(&cif, FFI_FN(struct3), ts3_result, values);
-
-    printf ("%d %d\n", ts3_result->si, -(compare_value*2));
-
-    if (ts3_result->si == -(ts3_arg.si*2))
-       puts ("structure test 3 ok!");
-    else
-      {
-       puts ("Structure test 3 found structure passing bug.");
-       puts ("  Current versions of GCC are not 100% compliant with the");
-       puts ("  n32 ABI.  There is a known problem related to passing");
-       puts ("  small structures.  Send a bug report to the gcc maintainers.");
-      }
-
-    free (ts3_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_4 ts4_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_4 *ts4_result = 
-      (test_structure_4 *) malloc (sizeof(test_structure_4));
-
-    args[0] = &ts4_type;
-    values[0] = &ts4_arg;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK);
-
-    ts4_arg.ui1 = 2;
-    ts4_arg.ui2 = 3;
-    ts4_arg.ui3 = 4;
-
-    ffi_call (&cif, FFI_FN(struct4), ts4_result, values);
-    
-    if (ts4_result->ui3 == 2U * 3U * 4U)
-      puts ("structure test 4 ok!");
-    else
-      puts ("Structure test 4 found GCC's structure passing bug.");
-
-    free (ts4_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_5 ts5_arg1, ts5_arg2;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_5 *ts5_result = 
-      (test_structure_5 *) malloc (sizeof(test_structure_5));
-
-    args[0] = &ts5_type;
-    args[1] = &ts5_type;
-    values[0] = &ts5_arg1;
-    values[1] = &ts5_arg2;
-    
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK);
-
-    ts5_arg1.c1 = 2;
-    ts5_arg1.c2 = 6;
-    ts5_arg2.c1 = 5;
-    ts5_arg2.c2 = 3;
-
-    ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
-    
-    if (ts5_result->c1 == 7 
-       && ts5_result->c2 == 3)
-      puts ("structure test 5 ok!");
-    else
-      puts ("Structure test 5 found GCC's structure passing bug.");
-
-    free (ts5_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_6 ts6_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_6 *ts6_result = 
-      (test_structure_6 *) malloc (sizeof(test_structure_6));
-
-    args[0] = &ts6_type;
-    values[0] = &ts6_arg;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts6_type, args) == FFI_OK);
-
-    ts6_arg.f = 5.55f;
-    ts6_arg.d = 6.66;
-
-    printf ("%g\n", ts6_arg.f);
-    printf ("%g\n", ts6_arg.d);
-
-    ffi_call(&cif, FFI_FN(struct6), ts6_result, values);
-
-    printf ("%g\n", ts6_result->f);
-    printf ("%g\n", ts6_result->d);
-
-    CHECK(ts6_result->f == 5.55f + 1);
-    CHECK(ts6_result->d == 6.66 + 1);
-
-    printf("structure test 6 ok!\n");
-
-    free (ts6_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_7 ts7_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_7 *ts7_result = 
-      (test_structure_7 *) malloc (sizeof(test_structure_7));
-
-    args[0] = &ts7_type;
-    values[0] = &ts7_arg;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts7_type, args) == FFI_OK);
-
-    ts7_arg.f1 = 5.55f;
-    ts7_arg.f2 = 55.5f;
-    ts7_arg.d = 6.66;
-
-    printf ("%g\n", ts7_arg.f1);
-    printf ("%g\n", ts7_arg.f2);
-    printf ("%g\n", ts7_arg.d);
-
-    ffi_call(&cif, FFI_FN(struct7), ts7_result, values);
-
-    printf ("%g\n", ts7_result->f1);
-    printf ("%g\n", ts7_result->f2);
-    printf ("%g\n", ts7_result->d);
-
-    CHECK(ts7_result->f1 == 5.55f + 1);
-    CHECK(ts7_result->f2 == 55.5f + 1);
-    CHECK(ts7_result->d == 6.66 + 1);
-
-    printf("structure test 7 ok!\n");
-
-    free (ts7_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_8 ts8_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_8 *ts8_result = 
-      (test_structure_8 *) malloc (sizeof(test_structure_8));
-
-    args[0] = &ts8_type;
-    values[0] = &ts8_arg;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts8_type, args) == FFI_OK);
-
-    ts8_arg.f1 = 5.55f;
-    ts8_arg.f2 = 55.5f;
-    ts8_arg.f3 = -5.55f;
-    ts8_arg.f4 = -55.5f;
-
-    printf ("%g\n", ts8_arg.f1);
-    printf ("%g\n", ts8_arg.f2);
-    printf ("%g\n", ts8_arg.f3);
-    printf ("%g\n", ts8_arg.f4);
-
-    ffi_call(&cif, FFI_FN(struct8), ts8_result, values);
-
-    printf ("%g\n", ts8_result->f1);
-    printf ("%g\n", ts8_result->f2);
-    printf ("%g\n", ts8_result->f3);
-    printf ("%g\n", ts8_result->f4);
-
-    CHECK(ts8_result->f1 == 5.55f + 1);
-    CHECK(ts8_result->f2 == 55.5f + 1);
-    CHECK(ts8_result->f3 == -5.55f + 1);
-    CHECK(ts8_result->f4 == -55.5f + 1);
-
-    printf("structure test 8 ok!\n");
-
-    free (ts8_result);
-  }
-
-  /* struct tests */
-  {
-    test_structure_9 ts9_arg;
-
-    /* This is a hack to get a properly aligned result buffer */
-    test_structure_9 *ts9_result = 
-      (test_structure_9 *) malloc (sizeof(test_structure_9));
-
-    args[0] = &ts9_type;
-    values[0] = &ts9_arg;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts9_type, args) == FFI_OK);
-
-    ts9_arg.f = 5.55f;
-    ts9_arg.i = 5;
-
-    printf ("%g\n", ts9_arg.f);
-    printf ("%d\n", ts9_arg.i);
-
-    ffi_call(&cif, FFI_FN(struct9), ts9_result, values);
-
-    printf ("%g\n", ts9_result->f);
-    printf ("%d\n", ts9_result->i);
-
-    CHECK(ts9_result->f == 5.55f + 1);
-    CHECK(ts9_result->i == 5 + 1);
-
-    printf("structure test 9 ok!\n");
-
-    free (ts9_result);
-  }
-
-#else
-  printf("Structure passing doesn't work on Win32.\n");
-#endif /* X86_WIN32 */
-
-#ifdef X86_WIN32
-  /* stdcall strlen tests */
-  {
-    args[0] = &ffi_type_pointer;
-    values[0] = (void*) &s;
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 1,
-                      &ffi_type_sint, args) == FFI_OK);
-
-    s = "a";
-    ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
-    CHECK(rint == 1);
-
-    s = "1234567";
-    ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
-    CHECK(rint == 7);
-
-    s = "1234567890123456789012345";
-    ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
-    CHECK(rint == 25);
-
-    printf("stdcall strlen tests passed\n");
-  }
-
-  /* stdcall many arg tests */
-  {
-    float ff;
-    float fa[13];
-
-    for (ul = 0; ul < 13; ul++)
-      {
-       args[ul] = &ffi_type_float;
-       values[ul] = &fa[ul];
-       fa[ul] = (float) ul;
-      }
-
-    /* Initialize the cif */
-    CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 13,
-                      &ffi_type_float, args) == FFI_OK);
-
-    /address@hidden@*/
-    ff =  stdcall_many(fa[0], fa[1],
-              fa[2], fa[3],
-              fa[4], fa[5],
-              fa[6], fa[7],
-              fa[8], fa[9],
-              fa[10],fa[11],fa[12]);
-    /address@hidden@*/
-
-    ffi_call(&cif, FFI_FN(stdcall_many), &f, values);
-
-    /address@hidden@*/
-    if (f - ff < FLT_EPSILON)
-    /address@hidden@*/
-       printf("stdcall many arg tests ok!\n");
-    else
-        CHECK(0);
-  }
-#endif /* X86_WIN32 */
-
-# if FFI_CLOSURES
-#  if __GNUC__ >= 2
-   /* Hide before the compiler that pcl is &cl, since on
-      some architectures it is not possible to call a data
-      object using direct function call.  */
-   asm ("" : "=g" (pcl) : "0" (pcl));
-#  endif
-
-  /* A simple closure test */
-    {
-      (void) puts("\nEnter FFI_CLOSURES\n");
-
-      cl_arg_types[0] = &ffi_type_uint64;
-      cl_arg_types[1] = &ffi_type_uint;
-      cl_arg_types[2] = &ffi_type_uint64;
-      cl_arg_types[3] = &ffi_type_uint;
-      cl_arg_types[4] = &ffi_type_sshort;
-      cl_arg_types[5] = &ffi_type_uint64;
-      cl_arg_types[6] = &ffi_type_uint;
-      cl_arg_types[7] = &ffi_type_uint;
-      cl_arg_types[8] = &ffi_type_double;
-      cl_arg_types[9] = &ffi_type_uint;
-      cl_arg_types[10] = &ffi_type_uint;
-      cl_arg_types[11] = &ffi_type_float;
-      cl_arg_types[12] = &ffi_type_uint;
-      cl_arg_types[13] = &ffi_type_uint;
-      cl_arg_types[14] = &ffi_type_uint;
-      cl_arg_types[15] = &ffi_type_uint;
-      cl_arg_types[16] = NULL;   
-
-      /* Initialize the cif */
-      CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
-                        &ffi_type_sint, cl_arg_types) == FFI_OK);
-
-      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn,
-                            (void *) 3 /* userdata */) == FFI_OK);
-      
-      CHECK((*((closure_test_type)pcl))
-           (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13, 
-            19, 21, 1) == 680);
-    }
-
-    {
-
-      cl_arg_types[0] = &ffi_type_float;
-      cl_arg_types[1] = &ffi_type_float;
-      cl_arg_types[2] = &ffi_type_float;
-      cl_arg_types[3] = &ffi_type_float;
-      cl_arg_types[4] = &ffi_type_sshort;
-      cl_arg_types[5] = &ffi_type_float;
-      cl_arg_types[6] = &ffi_type_float;
-      cl_arg_types[7] = &ffi_type_uint;
-      cl_arg_types[8] = &ffi_type_double;
-      cl_arg_types[9] = &ffi_type_uint;
-      cl_arg_types[10] = &ffi_type_uint;
-      cl_arg_types[11] = &ffi_type_float;
-      cl_arg_types[12] = &ffi_type_uint;
-      cl_arg_types[13] = &ffi_type_uint;
-      cl_arg_types[14] = &ffi_type_uint;
-      cl_arg_types[15] = &ffi_type_uint;
-      cl_arg_types[16] = NULL;
-      
-      /* Initialize the cif */
-      CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
-                        &ffi_type_sint, cl_arg_types) == FFI_OK);
-
-      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn1,
-                            (void *) 3 /* userdata */)  == FFI_OK);
-      
-      CHECK((*((closure_test_type1)pcl))
-           (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
-            19, 21, 1) == 255);
-    }
-
-    {
-
-      cl_arg_types[0] = &ffi_type_double;
-      cl_arg_types[1] = &ffi_type_double;
-      cl_arg_types[2] = &ffi_type_double;
-      cl_arg_types[3] = &ffi_type_double;
-      cl_arg_types[4] = &ffi_type_sshort;
-      cl_arg_types[5] = &ffi_type_double;
-      cl_arg_types[6] = &ffi_type_double;
-      cl_arg_types[7] = &ffi_type_uint;
-      cl_arg_types[8] = &ffi_type_double;
-      cl_arg_types[9] = &ffi_type_uint;
-      cl_arg_types[10] = &ffi_type_uint;
-      cl_arg_types[11] = &ffi_type_float;
-      cl_arg_types[12] = &ffi_type_uint;
-      cl_arg_types[13] = &ffi_type_float;
-      cl_arg_types[14] = &ffi_type_uint;
-      cl_arg_types[15] = &ffi_type_uint;
-      cl_arg_types[16] = NULL;
-      
-      /* Initialize the cif */
-      CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
-                        &ffi_type_sint, cl_arg_types) == FFI_OK);
-
-      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn2,
-                            (void *) 3 /* userdata */) == FFI_OK);
-
-      CHECK((*((closure_test_type2)pcl))
-           (1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13,
-            19.0, 21, 1) == 255);
-
-    }
-
-    {
-
-      cl_arg_types[0] = &ffi_type_float;
-      cl_arg_types[1] = &ffi_type_float;
-      cl_arg_types[2] = &ffi_type_float;
-      cl_arg_types[3] = &ffi_type_float;
-      cl_arg_types[4] = &ffi_type_float;
-      cl_arg_types[5] = &ffi_type_float;
-      cl_arg_types[6] = &ffi_type_float;
-      cl_arg_types[7] = &ffi_type_float;
-      cl_arg_types[8] = &ffi_type_double;
-      cl_arg_types[9] = &ffi_type_uint;
-      cl_arg_types[10] = &ffi_type_float;
-      cl_arg_types[11] = &ffi_type_float;
-      cl_arg_types[12] = &ffi_type_uint;
-      cl_arg_types[13] = &ffi_type_float;
-      cl_arg_types[14] = &ffi_type_float;
-      cl_arg_types[15] = &ffi_type_uint;
-      cl_arg_types[16] = NULL;
-      
-      /* Initialize the cif */
-      CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
-                        &ffi_type_sint, cl_arg_types) == FFI_OK);
-
-      CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn3,
-                            (void *) 3 /* userdata */)  == FFI_OK);
-      
-      CHECK((*((closure_test_type3)pcl))
-           (1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9, 10, 11.11, 12.0, 13,
-            19.19, 21.21, 1) == 135);
-    }
-
-    (void) puts("\nFinished FFI_CLOSURES\n");
-
-# endif
-
-  /* If we arrived here, all is good */
-  (void) puts("\nLooks good. No surprises.\n");
-
-  /address@hidden@*/
-
-  return 0;
-}
-




reply via email to

[Prev in Thread] Current Thread [Next in Thread]