[Top][All Lists]
[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] = ≪
-
- /* 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] = ≻
-
- /* 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] = ≻
- 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;
-}
-
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] pnet ChangeLog libffi/ChangeLog libffi/Makefile...,
Klaus Treichel <=