Import libffi-3.0.4, and use it to provide FFI support in GHCi
authorSimon Marlow <simonmar@microsoft.com>
Tue, 8 Apr 2008 18:34:34 +0000 (18:34 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Tue, 8 Apr 2008 18:34:34 +0000 (18:34 +0000)
This replaces the hand-rolled architecture-specific FFI support in
GHCi with the standard libffi as used in GCJ, Python and other
projects.  I've bundled the complete libffi-3.0.4 tarball in the
source tree in the same way as we do for GMP, the difference being
that we always build and install our own libffi regardless of whether
there's one on the system (it's small, and we don't want
dependency/versioning headaches).

In particular this means that unregisterised builds will now have a
fully working GHCi including FFI out of the box, provided libffi
supports the platform.

There is also code in the RTS to use libffi in place of
rts/Adjustor.c, but it is currently not enabled if we already have
support in Adjustor.c for the current platform.  We need to assess the
performance impact before using libffi here too (in GHCi we don't care
too much about performance).

12 files changed:
Makefile
compiler/Makefile
compiler/ghci/ByteCodeFFI.lhs
compiler/ghci/ByteCodeGen.lhs
compiler/ghci/LibFFI.hsc
libffi/Makefile [new file with mode: 0644]
libffi/libffi-3.0.4.tar.gz [new file with mode: 0644]
rts/Adjustor.c
rts/Interpreter.c
rts/Linker.c
rts/Makefile
rts/package.conf.in

index e6d9866..870e0c4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -67,12 +67,12 @@ include $(TOP)/mk/boilerplate.mk
 
 # We can't 'make boot' in libraries until stage1 is built
 ifeq "$(BootingFromHc)" "YES"
 
 # We can't 'make boot' in libraries until stage1 is built
 ifeq "$(BootingFromHc)" "YES"
-SUBDIRS_BUILD = gmp includes rts compat compiler docs utils driver
+SUBDIRS_BUILD = gmp libffi includes rts compat compiler docs utils driver
 else
 else
-SUBDIRS_BUILD = gmp includes compat utils driver docs compiler rts libraries/Cabal/doc
+SUBDIRS_BUILD = gmp libffi includes compat utils driver docs compiler rts libraries/Cabal/doc
 endif
 
 endif
 
-SUBDIRS = gmp includes compat utils driver docs rts libraries compiler libraries/Cabal/doc
+SUBDIRS = gmp libffi includes compat utils driver docs rts libraries compiler libraries/Cabal/doc
 
 # Sanity check that all the boot libraries are in the tree, to catch
 # failure to run darcs-all.
 
 # Sanity check that all the boot libraries are in the tree, to catch
 # failure to run darcs-all.
index 2dd6203..216e5f8 100644 (file)
@@ -308,7 +308,7 @@ else
        @echo "cRelocatableBuild     = False"                 >> $(CONFIG_HS)
 endif
        @echo "cLibFFI               :: Bool"                 >> $(CONFIG_HS)
        @echo "cRelocatableBuild     = False"                 >> $(CONFIG_HS)
 endif
        @echo "cLibFFI               :: Bool"                 >> $(CONFIG_HS)
-ifeq "$(UseLibFFI)" "YES"
+ifeq "$(UseLibFFIForAdjustors)" "YES"
        @echo "cLibFFI               = True"                  >> $(CONFIG_HS)
 else
        @echo "cLibFFI               = False"                 >> $(CONFIG_HS)
        @echo "cLibFFI               = True"                  >> $(CONFIG_HS)
 else
        @echo "cLibFFI               = False"                 >> $(CONFIG_HS)
@@ -457,11 +457,6 @@ ALL_DIRS += javaGen
 SRC_HC_OPTS += -DJAVA
 endif
 
 SRC_HC_OPTS += -DJAVA
 endif
 
-ifeq ($(UseLibFFI),YES)
-SRC_HC_OPTS += -DUSE_LIBFFI
-SRC_HSC2HS_OPTS += -DUSE_LIBFFI
-endif
-
 ifeq "$(BootingFromHc)" "YES"
 # HC files are always from a self-booted compiler
 bootstrapped = YES
 ifeq "$(BootingFromHc)" "YES"
 # HC files are always from a self-booted compiler
 bootstrapped = YES
@@ -517,6 +512,9 @@ ifeq "$(GhcDebugged)" "YES"
 SRC_LD_OPTS += -debug
 endif
 
 SRC_LD_OPTS += -debug
 endif
 
+SRC_HC_OPTS     += -I$(FPTOOLS_TOP)/libffi/build/include
+SRC_HSC2HS_OPTS += -I$(FPTOOLS_TOP)/libffi/build/include
+
 ALL_DIRS += ghci
 
 # If we are going to use dynamic libraries instead of .o files for ghci,
 ALL_DIRS += ghci
 
 # If we are going to use dynamic libraries instead of .o files for ghci,
index d72f1ac..5c2b35f 100644 (file)
@@ -1,19 +1,10 @@
 %
 %
-% (c) The University of Glasgow 2001-2006
+% (c) The University of Glasgow 2001-2008
 %
 
 ByteCodeGen: Generate machine-code sequences for foreign import
 
 \begin{code}
 %
 
 ByteCodeGen: Generate machine-code sequences for foreign import
 
 \begin{code}
-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
---     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
--- for details
-
-#ifdef USE_LIBFFI
-
 module ByteCodeFFI ( moan64, newExec ) where
 
 import Outputable
 module ByteCodeFFI ( moan64, newExec ) where
 
 import Outputable
@@ -21,844 +12,6 @@ import System.IO
 import Foreign
 import Foreign.C
 
 import Foreign
 import Foreign.C
 
-#else
-
-module ByteCodeFFI ( mkMarshalCode, moan64, newExec ) where
-
-#include "HsVersions.h"
-
-import TyCon
-import Outputable
-import SMRep
-import ForeignCall
-import Panic
-
--- DON'T remove apparently unused imports here .. 
--- there is ifdeffery below
-import Control.Exception ( throwDyn )
-import Data.Bits       ( Bits(..), shiftR, shiftL )
-import Data.List        ( mapAccumL )
-
-import Data.Word       ( Word8, Word32 )
-import Foreign         ( Ptr, FunPtr, castPtrToFunPtr,
-                         Storable, sizeOf, pokeArray )
-import Foreign.C       ( CUInt )
-import System.IO.Unsafe ( unsafePerformIO )
-import System.IO       ( hPutStrLn, stderr )
--- import Debug.Trace  ( trace )
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{The platform-dependent marshall-code-generator.}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-
--- For sparc_TARGET_ARCH, i386_TARGET_ARCH, etc.
-#include "nativeGen/NCG.h"
-
-{-
-Make a piece of code which expects to see the Haskell stack
-looking like this.  It is given a pointer to the lowest word in
-the stack -- presumably the tag of the placeholder.
-                 
-                  <arg_n>
-                  ...
-                  <arg_1>
-                  Addr# address_of_C_fn
-                  <placeholder-for-result#> (must be an unboxed type)
-
-We cope with both ccall and stdcall for the C fn.  However, this code
-itself expects only to be called using the ccall convention -- that is,
-we don't clear our own (single) arg off the C stack.
--}
-mkMarshalCode :: CCallConv
-              -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] 
-              -> IO (FunPtr ())
-mkMarshalCode cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
-   = let bytes = mkMarshalCode_wrk cconv (r_offW, r_rep) 
-                                   addr_offW arg_offs_n_reps
-     in  newExec bytes
-
-mkMarshalCode_wrk :: CCallConv 
-                  -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] 
-                  -> [Word8]
-
-mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
-
-#if i386_TARGET_ARCH
-
-   = let -- Don't change this without first consulting Intel Corp :-)
-         bytes_per_word = 4
-
-         offsets_to_pushW
-            = concat
-              [   -- reversed because x86 is little-endian
-                  reverse [a_offW .. a_offW + primRepSizeW a_rep - 1]
-
-                -- reversed because args are pushed L -> R onto C stack
-                | (a_offW, a_rep) <- reverse arg_offs_n_reps
-              ]
-         
-         arguments_size = bytes_per_word * length offsets_to_pushW
-#if darwin_TARGET_OS
-             -- Darwin: align stack frame size to a multiple of 16 bytes
-         stack_frame_size = (arguments_size + 15) .&. complement 15
-         stack_frame_pad = stack_frame_size - arguments_size
-#else
-         stack_frame_size = arguments_size
-#endif
-
-         -- some helpers to assemble x86 insns.
-         movl_offespmem_esi offB       -- movl   offB(%esp), %esi
-            = [0x8B, 0xB4, 0x24] ++ lit32 offB
-         movl_offesimem_ecx offB       -- movl   offB(%esi), %ecx
-            = [0x8B, 0x8E] ++ lit32 offB
-         save_regs                     -- pushl  all intregs except %esp
-            = [0x50, 0x53, 0x51, 0x52, 0x56, 0x57, 0x55]
-         restore_regs                  -- popl   ditto
-            = [0x5D, 0x5F, 0x5E, 0x5A, 0x59, 0x5B, 0x58]
-         pushl_ecx                     -- pushl  %ecx
-            = [0x51]
-         call_star_ecx                 -- call   * %ecx
-            = [0xFF, 0xD1]
-         add_lit_esp lit               -- addl   $lit, %esp
-            = [0x81, 0xC4] ++ lit32 lit
-         movl_eax_offesimem offB       -- movl   %eax, offB(%esi)
-            = [0x89, 0x86] ++ lit32 offB
-         movl_edx_offesimem offB       -- movl   %edx, offB(%esi)
-            = [0x89, 0x96] ++ lit32 offB
-         ret                           -- ret
-            = [0xC3]
-         fstpl_offesimem offB          -- fstpl   offB(%esi)
-            = [0xDD, 0x9E] ++ lit32 offB
-         fstps_offesimem offB          -- fstps   offB(%esi)
-            = [0xD9, 0x9E] ++ lit32 offB
-         {-
-             2 0000 8BB42478    movl    0x12345678(%esp), %esi
-             2      563412
-             3 0007 8B8E7856    movl    0x12345678(%esi), %ecx
-             3      3412
-             4              
-             5 000d 50535152    pushl %eax ; pushl %ebx ; pushl %ecx ; pushl  %edx
-             6 0011 565755      pushl %esi ; pushl %edi ; pushl %ebp
-             7              
-             8 0014 5D5F5E      popl %ebp ; popl %edi ; popl %esi 
-             9 0017 5A595B58    popl %edx ; popl %ecx ; popl %ebx ; popl %eax
-            10              
-            11 001b 51          pushl %ecx
-            12 001c FFD1        call * %ecx
-            13              
-            14 001e 81C47856    addl $0x12345678, %esp
-            14      3412
-            15 0024 89867856    movl %eax, 0x12345678(%esi)
-            15      3412
-            16 002a 89967856    movl %edx, 0x12345678(%esi)
-            16      3412
-            17           
-            18 0030 DD967856    fstl    0x12345678(%esi)
-            18      3412
-            19 0036 DD9E7856    fstpl   0x12345678(%esi)
-            19      3412
-            20 003c D9967856    fsts    0x12345678(%esi)
-            20      3412
-            21 0042 D99E7856    fstps   0x12345678(%esi)
-            18              
-            19 0030 C3          ret
-            20              
-
-         -}
-
-     in
-     --trace (show (map fst arg_offs_n_reps))
-     (
-     {- On entry, top of C stack 0(%esp) is the RA and 4(%esp) is 
-        arg passed from the interpreter.
-
-        Push all callee saved regs.  Push all of them anyway ...
-           pushl       %eax
-           pushl       %ebx
-           pushl       %ecx
-           pushl       %edx
-           pushl       %esi
-           pushl       %edi
-           pushl       %ebp
-     -}
-     save_regs
-
-     {- Now 28+0(%esp) is RA and 28+4(%esp) is the arg (the H stack ptr).
-        We'll use %esi as a temporary to point at the H stack, and
-        %ecx as a temporary to copy via.
-
-           movl        28+4(%esp), %esi
-     -}
-     ++ movl_offespmem_esi 32
-
-#if darwin_TARGET_OS
-     {- On Darwin, add some padding so that the stack stays aligned. -}
-     ++ (if stack_frame_pad /= 0
-            then add_lit_esp (-stack_frame_pad)
-            else [])
-#endif
-
-     {- For each arg in args_offs_n_reps, examine the associated
-        CgRep to determine how many words there are.  This gives a
-        bunch of offsets on the H stack to copy to the C stack:
-
-           movl        off1(%esi), %ecx
-           pushl       %ecx
-     -}
-     ++ concatMap (\offW -> movl_offesimem_ecx (bytes_per_word * offW) 
-                            ++ pushl_ecx) 
-                  offsets_to_pushW
-
-     {- Get the addr to call into %ecx, bearing in mind that there's 
-        an Addr# tag at the indicated location, and do the call:
-
-           movl        4*(1 /*tag*/ +addr_offW)(%esi), %ecx
-           call        * %ecx
-     -}
-     ++ movl_offesimem_ecx (bytes_per_word * addr_offW)
-     ++ call_star_ecx
-
-     {- Nuke the args just pushed and re-establish %esi at the 
-        H-stack ptr:
-
-           addl        $4*number_of_args_pushed, %esp (ccall only)
-           movl        28+4(%esp), %esi
-     -}
-     ++ (if   cconv /= StdCallConv
-         then add_lit_esp stack_frame_size
-         else [])
-     ++ movl_offespmem_esi 32
-
-     {- Depending on what the return type is, get the result 
-        from %eax or %edx:%eax or %st(0).
-
-           movl        %eax, 4(%esi)        -- assuming tagged result
-        or
-           movl        %edx, 4(%esi)
-           movl        %eax, 8(%esi)
-        or
-           fstpl       4(%esi)
-        or
-           fstps       4(%esi)
-     -}
-     ++ let i32 = movl_eax_offesimem 0
-            i64 = movl_eax_offesimem 0 ++ movl_edx_offesimem 4
-            f32 = fstps_offesimem 0
-            f64 = fstpl_offesimem 0
-        in
-        case r_rep of
-           VoidRep   -> []
-           IntRep    -> i32
-           WordRep   -> i32
-           Int64Rep  -> i64
-           Word64Rep -> i64
-           AddrRep   -> i32
-           FloatRep  -> f32
-           DoubleRep -> f64
-           other     -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(x86)" 
-                               (ppr r_rep)
-
-     {- Restore all the pushed regs and go home.
-
-           pushl        %ebp
-           pushl        %edi
-           pushl        %esi
-           pushl        %edx
-           pushl        %ecx
-           pushl        %ebx
-           pushl        %eax
-
-           ret
-     -}
-     ++ restore_regs
-     ++ ret
-     )
-
-#elif x86_64_TARGET_ARCH
-
-   =
-     -- the address of the H stack is in %rdi.  We need to move it out, so
-     -- we can use %rdi as an arg reg for the following call:
-    pushq_rbp ++
-    movq_rdi_rbp ++
-       
-     -- ####### load / push the args
-
-     let
-       (stack_args, fregs_unused, reg_loads) = 
-          load_arg_regs arg_offs_n_reps int_loads float_loads []
-
-       tot_arg_size = bytes_per_word * length stack_args
-
-       -- On entry to the called function, %rsp should be aligned
-       -- on a 16-byte boundary +8 (i.e. the first stack arg after
-       -- the return address is 16-byte aligned).  In STG land
-       -- %rsp is kept 16-byte aligned (see StgCRun.c), so we just
-       -- need to make sure we push a multiple of 16-bytes of args,
-       -- plus the return address, to get the correct alignment.
-       (real_size, adjust_rsp)
-         | tot_arg_size `rem` 16 == 0    = (tot_arg_size, [])
-         | otherwise                     = (tot_arg_size + 8, subq_lit_rsp 8)
-
-       (stack_pushes, stack_words) =
-               push_args stack_args [] 0
-
-       -- we need to know the number of SSE regs used in the call, see later
-       n_sse_regs_used = length float_loads - length fregs_unused
-     in
-        concat reg_loads
-     ++ adjust_rsp
-     ++ concat stack_pushes -- push in reverse order
-
-     -- ####### make the call
-
-       -- use %r10 to make the call, because we don't have to save it.
-        --      movq 8*addr_offW(%rbp), %r10
-     ++ movq_rbpoff_r10 (bytes_per_word * addr_offW)
-
-       -- The x86_64 ABI requires us to set %al to the number of SSE
-       -- registers that contain arguments, if the called routine
-       -- is a varargs function.  We don't know whether it's a
-       -- varargs function or not, so we have to assume it is.
-       --
-       -- It's not safe to omit this assignment, even if the number
-       -- of SSE regs in use is zero.  If %al is larger than 8
-       -- on entry to a varargs function, seg faults ensue.
-     ++ movq_lit_rax n_sse_regs_used
-     ++ call_star_r10
-
-       -- pop the args from the stack, only in ccall mode 
-       -- (in stdcall the callee does it).
-     ++ (if   cconv /= StdCallConv
-         then addq_lit_rsp real_size
-         else [])
-
-     -- ####### place the result in the right place and return
-
-     ++ assign_result
-     ++ popq_rbp
-     ++ ret
-
-  where
-     bytes_per_word = 8
-
-     -- int arg regs: rdi,rsi,rdx,rcx,r8,r9
-     -- flt arg regs: xmm0..xmm7
-     int_loads   = [ movq_rbpoff_rdi, movq_rbpoff_rsi, movq_rbpoff_rdx,
-                    movq_rbpoff_rcx, movq_rbpoff_r8,  movq_rbpoff_r9 ]
-     float_loads = [ 0..7 ]
-
-     load_arg_regs args [] [] code     =  (args, [], code)
-     load_arg_regs [] iregs fregs code =  ([], fregs, code)
-     load_arg_regs ((off,rep):args) iregs fregs code
-       | FloatRep  <- rep =
-            case fregs of
-              [] -> push_this_arg
-              n : frest ->
-               load_arg_regs args iregs frest 
-                      (mov_f32_rbpoff_xmm n (bytes_per_word * off) : code)
-       | DoubleRep <- rep =
-            case fregs of
-              [] -> push_this_arg
-              n : frest ->
-               load_arg_regs args iregs frest 
-                       (mov_f64_rbpoff_xmm n (bytes_per_word * off) : code)
-       | (mov_reg:irest) <- iregs =
-               load_arg_regs args irest fregs (mov_reg (bytes_per_word * off) : code)
-       | otherwise =
-                push_this_arg
-       where
-          push_this_arg = ((off,rep):args',fregs', code')
-               where (args',fregs',code') = load_arg_regs args iregs fregs code
-
-     push_args [] code pushed_words = (code, pushed_words)
-     push_args ((off,rep):args) code pushed_words
-       | FloatRep  <- rep =
-               push_args args (push_f32_rbpoff (bytes_per_word * off) : code) 
-                       (pushed_words+1)
-       | DoubleRep <- rep =
-               push_args args (push_f64_rbpoff (bytes_per_word * off) : code)
-                       (pushed_words+1)
-       | otherwise =
-               push_args args (pushq_rbpoff (bytes_per_word * off) : code)
-                       (pushed_words+1)
-
-
-     assign_result = 
-       case r_rep of
-         DoubleRep -> f64
-         FloatRep  -> f32
-          VoidRep   -> []
-         _other    -> i64
-       where
-         i64 = movq_rax_rbpoff 0
-         f32 = mov_f32_xmm0_rbpoff 0
-         f64 = mov_f64_xmm0_rbpoff 0
-
---    ######### x86_64 machine code:
-
---   0:   48 89 fd                mov    %rdi,%rbp
---   3:   48 8b bd 78 56 34 12    mov    0x12345678(%rbp),%rdi
---   a:   48 8b b5 78 56 34 12    mov    0x12345678(%rbp),%rsi
---  11:   48 8b 95 78 56 34 12    mov    0x12345678(%rbp),%rdx
---  18:   48 8b 8d 78 56 34 12    mov    0x12345678(%rbp),%rcx
---  1f:   4c 8b 85 78 56 34 12    mov    0x12345678(%rbp),%r8
---  26:   4c 8b 8d 78 56 34 12    mov    0x12345678(%rbp),%r9
---  2d:   4c 8b 95 78 56 34 12    mov    0x12345678(%rbp),%r10
---  34:   48 c7 c0 78 56 34 12    mov    $0x12345678,%rax
---  3b:   48 89 85 78 56 34 12    mov    %rax,0x12345678(%rbp)
---  42:   f3 0f 10 bd 78 56 34 12 movss  0x12345678(%rbp),%xmm7
---  4a:   f2 0f 10 9d 78 56 34 12 movsd  0x12345678(%rbp),%xmm3
---  52:   f2 44 0f 10 85 78 56 34 12 movsd  0x12345678(%rbp),%xmm8
---  5b:   f3 0f 11 9d 78 56 34 12 movss  %xmm3,0x12345678(%rbp)
---  63:   f2 0f 11 9d 78 56 34 12 movsd  %xmm3,0x12345678(%rbp)
---  6b:   f2 44 0f 11 85 78 56 34 12 movsd  %xmm8,0x12345678(%rbp)
---  74:   ff b5 78 56 34 12       pushq  0x12345678(%rbp)
---  7a:   f3 44 0f 11 04 24       movss  %xmm8,(%rsp)
---  80:   f2 44 0f 11 04 24       movsd  %xmm8,(%rsp)
---  86:   48 81 ec 78 56 34 12    sub    $0x12345678,%rsp
---  8d:   48 81 c4 78 56 34 12    add    $0x12345678,%rsp
---  94:   41 ff d2                callq  *%r10
---  97:   55                      push   %rbp
---  98:   5d                      pop    %rbp
---  99:   c3                      retq   
-
-     movq_rdi_rbp         = [0x48,0x89,0xfd]
-     movq_rbpoff_rdi  off = [0x48, 0x8b, 0xbd] ++ lit32 off
-     movq_rbpoff_rsi  off = [0x48, 0x8b, 0xb5] ++ lit32 off
-     movq_rbpoff_rdx  off = [0x48, 0x8b, 0x95] ++ lit32 off
-     movq_rbpoff_rcx  off = [0x48, 0x8b, 0x8d] ++ lit32 off 
-     movq_rbpoff_r8   off = [0x4c, 0x8b, 0x85] ++ lit32 off
-     movq_rbpoff_r9   off = [0x4c, 0x8b, 0x8d] ++ lit32 off
-     movq_rbpoff_r10  off = [0x4c, 0x8b, 0x95] ++ lit32 off
-     movq_lit_rax     lit = [0x48, 0xc7, 0xc0] ++ lit32 lit
-     movq_rax_rbpoff  off = [0x48, 0x89, 0x85] ++ lit32 off
-     mov_f32_rbpoff_xmm n off
-         = 0xf3 : if n >= 8 then 0x44 : rest else rest
-         where rest = [0x0f, 0x10, 0x85 + (n.&.7)`shiftL`3] ++ lit32 off
-     mov_f64_rbpoff_xmm n off
-         = 0xf2 : if n >= 8 then 0x44 : rest else rest
-         where rest = [0x0f, 0x10, 0x85 + (n.&.7)`shiftL`3] ++ lit32 off
-     mov_f32_xmm0_rbpoff  off = [0xf3, 0x0f, 0x11, 0x85] ++ lit32 off
-     mov_f64_xmm0_rbpoff  off = [0xf2, 0x0f, 0x11, 0x85] ++ lit32 off
-     pushq_rbpoff     off = [0xff, 0xb5] ++ lit32 off
-     push_f32_rbpoff  off = 
-       subq_lit_rsp 8 ++                        -- subq $8, %rsp
-       mov_f32_rbpoff_xmm 8 off ++              -- movss off(%rbp), %xmm8
-       [0xf3, 0x44, 0x0f, 0x11, 0x04, 0x24]     -- movss %xmm8, (%rsp)
-     push_f64_rbpoff  off =
-       subq_lit_rsp 8 ++                        -- subq $8, %rsp
-       mov_f64_rbpoff_xmm 8 off ++              -- movsd off(%rbp), %xmm8
-       [0xf2, 0x44, 0x0f, 0x11, 0x04, 0x24]     -- movsd %xmm8, (%rsp)
-     subq_lit_rsp     lit = [0x48, 0x81, 0xec] ++ lit32 lit
-     addq_lit_rsp     lit = [0x48, 0x81, 0xc4] ++ lit32 lit
-     call_star_r10 = [0x41,0xff,0xd2]
-     ret = [0xc3]
-     pushq_rbp = [0x55]
-     popq_rbp = [0x5d]
-
-#elif sparc_TARGET_ARCH
-
-   = let -- At least for sparc V8
-         bytes_per_word = 4
-
-         -- speaks for itself
-         w32_to_w8s_bigEndian :: Word32 -> [Word8]
-         w32_to_w8s_bigEndian w
-            =  [fromIntegral (0xFF .&. (w `shiftR` 24)),
-                fromIntegral (0xFF .&. (w `shiftR` 16)),
-                fromIntegral (0xFF .&. (w `shiftR` 8)),
-                fromIntegral (0xFF .&. w)]
-
-         offsets_to_pushW
-            = concat
-              [  [a_offW .. a_offW + primRepSizeW a_rep - 1]
-
-                | (a_offW, a_rep) <- arg_offs_n_reps
-              ]
-
-         total_argWs    = length offsets_to_pushW
-         argWs_on_stack = if total_argWs > 6 then total_argWs - 6 
-                                             else 0
-
-         -- The stack pointer must be kept 8-byte aligned, which means
-         -- we need to calculate this quantity too
-         argWs_on_stack_ROUNDED_UP
-            | odd argWs_on_stack = 1 + argWs_on_stack
-            | otherwise          = argWs_on_stack
-
-         -- some helpers to assemble sparc insns.
-         -- REGS
-         iReg, oReg, gReg, fReg :: Int -> Word32
-         iReg = fromIntegral . (+ 24)
-         oReg = fromIntegral . (+ 8)
-         gReg = fromIntegral . (+ 0)
-         fReg = fromIntegral
-
-         sp = oReg 6
-         i0 = iReg 0
-         i7 = iReg 7
-         o0 = oReg 0
-         o1 = oReg 1
-         o7 = oReg 7
-         g0 = gReg 0
-         g1 = gReg 1
-         f0 = fReg 0
-         f1 = fReg 1
-
-         -- INSN templates
-         insn_r_r_i :: Word32 -> Word32 -> Word32 -> Int -> Word32
-         insn_r_r_i op3 rs1 rd imm13
-            = (3 `shiftL` 30) 
-              .|. (rs1 `shiftL` 25)
-              .|. (op3 `shiftL` 19)
-              .|. (rd `shiftL` 14) 
-              .|. (1 `shiftL` 13) 
-              .|. mkSimm13 imm13
-
-         insn_r_i_r :: Word32 -> Word32 -> Int -> Word32 -> Word32
-         insn_r_i_r op3 rs1 imm13 rd
-            = (2 `shiftL` 30) 
-              .|. (rd `shiftL` 25)
-              .|. (op3 `shiftL` 19)
-              .|. (rs1 `shiftL` 14) 
-              .|. (1 `shiftL` 13) 
-              .|. mkSimm13 imm13
-
-         mkSimm13 :: Int -> Word32
-         mkSimm13 imm13 
-            = let imm13w = (fromIntegral imm13) :: Word32
-              in  imm13w .&. 0x1FFF             
-
-         -- REAL (non-synthetic) insns
-         -- or %rs1, %rs2, %rd
-         mkOR :: Word32 -> Word32 -> Word32 -> Word32
-         mkOR rs1 rs2 rd 
-            = (2 `shiftL` 30) 
-              .|. (rd `shiftL` 25)
-              .|. (op3_OR `shiftL` 19)
-              .|. (rs1 `shiftL` 14) 
-              .|. (0 `shiftL` 13) 
-              .|. rs2
-              where op3_OR = 2 :: Word32
-
-         -- ld(int)   [%rs + imm13], %rd
-         mkLD rs1 imm13 rd = insn_r_r_i 0x00{-op3_LD-} rd rs1 imm13
-
-         -- st(int)   %rs, [%rd + imm13]
-         mkST   = insn_r_r_i 0x04 -- op3_ST
-
-         -- st(float) %rs, [%rd + imm13]
-         mkSTF  = insn_r_r_i 0x24 -- op3_STF
-
-         -- jmpl     %rs + imm13, %rd
-         mkJMPL = insn_r_i_r 0x38 -- op3_JMPL
-
-         -- save     %rs + imm13, %rd
-         mkSAVE = insn_r_i_r 0x3C -- op3_SAVE
-
-         -- restore  %rs + imm13, %rd
-         mkRESTORE = insn_r_i_r 0x3D -- op3_RESTORE
-
-         -- SYNTHETIC insns
-         mkNOP             = mkOR g0 g0 g0
-         mkCALL reg        = mkJMPL reg 0 o7
-         mkRET             = mkJMPL i7 8 g0
-         mkRESTORE_TRIVIAL = mkRESTORE g0 0 g0
-     in
-     --trace (show (map fst arg_offs_n_reps))
-     concatMap w32_to_w8s_bigEndian (
-
-     {- On entry, %o0 is the arg passed from the interpreter.  After
-        the initial save insn, it will be in %i0.  Studying the sparc
-        docs one would have thought that the minimum frame size is 92
-        bytes, but gcc always uses at least 112, and indeed there are
-        segfaults a-plenty with 92.  So I use 112 here as well.  I
-        don't understand why, tho.  
-     -}
-     [mkSAVE sp (- ({-92-}112 + 4*argWs_on_stack_ROUNDED_UP)) sp]
-
-     {- For each arg in args_offs_n_reps, examine the associated
-        CgRep to determine how many words there are.  This gives a
-        bunch of offsets on the H stack.  Move the first 6 words into
-        %o0 .. %o5 and the rest on the stack, starting at [%sp+92].
-        Use %g1 as a temp. 
-     -}
-     ++ let doArgW (offW, wordNo)
-              | wordNo < 6
-              = [mkLD i0 (bytes_per_word * offW) (oReg wordNo)]
-              | otherwise
-              = [mkLD i0 (bytes_per_word * offW) g1,
-                 mkST g1 sp (92 + bytes_per_word * (wordNo - 6))]
-        in  
-            concatMap doArgW (zip offsets_to_pushW [0 ..])
-
-     {- Get the addr to call into %g1, bearing in mind that there's 
-        an Addr# tag at the indicated location, and do the call:
-
-           ld     [4*(1 /*tag*/ +addr_offW) + %i0], %g1
-           call   %g1
-     -}
-     ++ [mkLD i0 (bytes_per_word * addr_offW) g1,
-         mkCALL g1,
-         mkNOP]
-
-     {- Depending on what the return type is, get the result 
-        from %o0 or %o1:%o0 or %f0 or %f1:%f0.
-
-           st          %o0, [%i0 + 4]        -- 32 bit int
-        or
-           st          %o0, [%i0 + 4]        -- 64 bit int
-           st          %o1, [%i0 + 8]        -- or the other way round?
-        or
-           st          %f0, [%i0 + 4]        -- 32 bit float
-        or
-           st          %f0, [%i0 + 4]        -- 64 bit float
-           st          %f1, [%i0 + 8]        -- or the other way round?
-
-     -}
-     ++ let i32 = [mkST o0 i0 0]
-            i64 = [mkST o0 i0 0, mkST o1 i0 4]
-            f32 = [mkSTF f0 i0 0]
-            f64 = [mkSTF f0 i0 0, mkSTF f1 i0 4]
-        in
-            case r_rep of
-               VoidRep   -> []
-               IntRep    -> i32
-               WordRep   -> i32
-               AddrRep   -> i32
-               FloatRep  -> f32
-               DoubleRep -> f64
-               other     -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(sparc)" 
-                                   (ppr r_rep)
-
-     ++ [mkRET,
-         mkRESTORE_TRIVIAL]  -- this is in the delay slot of the RET
-     )
-#elif powerpc_TARGET_ARCH && darwin_TARGET_OS
-
-   = let
-         bytes_per_word = 4
-
-         -- speaks for itself
-         w32_to_w8s_bigEndian :: Word32 -> [Word8]
-         w32_to_w8s_bigEndian w
-            =  [fromIntegral (0xFF .&. (w `shiftR` 24)),
-                fromIntegral (0xFF .&. (w `shiftR` 16)),
-                fromIntegral (0xFF .&. (w `shiftR` 8)),
-                fromIntegral (0xFF .&. w)]
-
-         -- addr and result bits offsetsW
-         a_off = addr_offW * bytes_per_word
-         result_off  = r_offW * bytes_per_word
-
-         linkageArea = 24
-         parameterArea = sum [ primRepSizeW a_rep * bytes_per_word
-                        | (_, a_rep) <- arg_offs_n_reps ]
-         savedRegisterArea = 4
-         frameSize = padTo16 (linkageArea + max parameterArea 32 + savedRegisterArea)
-         padTo16 x = case x `mod` 16 of
-            0 -> x
-            y -> x - y + 16
-             
-         pass_parameters [] _ _ = []
-         pass_parameters ((a_offW, a_rep):args) nextFPR offsetW =
-            let
-               haskellArgOffset = a_offW * bytes_per_word
-               offsetW' = offsetW + primRepSizeW a_rep
-               
-               pass_word w 
-                   | offsetW + w < 8 =
-                      [0x801f0000    -- lwz rX, src(r31)
-                        .|. (fromIntegral src .&. 0xFFFF)
-                        .|. (fromIntegral (offsetW+w+3) `shiftL` 21)]
-                   | otherwise =
-                      [0x801f0000    -- lwz r0, src(r31)
-                        .|. (fromIntegral src .&. 0xFFFF),
-                       0x90010000    -- stw r0, dst(r1)
-                        .|. (fromIntegral dst .&. 0xFFFF)]
-                  where
-                     src = haskellArgOffset + w*bytes_per_word
-                     dst = linkageArea + (offsetW+w) * bytes_per_word
-            in
-               case a_rep of
-                  FloatRep | nextFPR < 14 ->
-                      (0xc01f0000    -- lfs fX, haskellArgOffset(r31)
-                        .|. (fromIntegral haskellArgOffset .&. 0xFFFF)
-                        .|. (fromIntegral nextFPR `shiftL` 21))
-                      : pass_parameters args (nextFPR+1) offsetW'
-                  DoubleRep | nextFPR < 14 ->
-                      (0xc81f0000    -- lfd fX, haskellArgOffset(r31)
-                        .|. (fromIntegral haskellArgOffset .&. 0xFFFF)
-                        .|. (fromIntegral nextFPR `shiftL` 21))
-                      : pass_parameters args (nextFPR+1) offsetW'
-                  _ ->
-                      concatMap pass_word [0 .. primRepSizeW a_rep - 1]
-                      ++ pass_parameters args nextFPR offsetW'              
-               
-         gather_result = case r_rep of
-            VoidRep -> []
-            FloatRep -> 
-               [0xd03f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
-               -- stfs f1, result_off(r31)
-            DoubleRep -> 
-               [0xd83f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
-               -- stfd f1, result_off(r31)
-            _ | primRepSizeW r_rep == 2 ->
-               [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF),
-                0x909f0000 .|. (fromIntegral (result_off+4) .&. 0xFFFF)]
-               -- stw r3, result_off(r31)
-               -- stw r4, result_off+4(r31)
-            _ | primRepSizeW r_rep == 1 ->
-               [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
-               -- stw r3, result_off(r31)
-     in
-         concatMap w32_to_w8s_bigEndian $ [
-            0x7c0802a6,         -- mflr r0
-            0x93e1fffc,         -- stw r31,-4(r1)
-            0x90010008,         -- stw r0,8(r1)
-            0x94210000 .|. (fromIntegral (-frameSize) .&. 0xFFFF),
-                                -- stwu r1, -frameSize(r1)
-            0x7c7f1b78          -- mr r31, r3
-         ] ++ pass_parameters arg_offs_n_reps 1 0 ++ [
-            0x819f0000 .|. (fromIntegral a_off .&. 0xFFFF),
-                                -- lwz r12, a_off(r31)
-            0x7d8903a6,         -- mtctr r12
-            0x4e800421          -- bctrl
-         ] ++ gather_result ++ [
-            0x80210000,         -- lwz r1, 0(r1)
-            0x83e1fffc,         -- lwz r31, -4(r1)
-            0x80010008,         -- lwz r0, 8(r1)
-            0x7c0803a6,         -- mtlr r0
-            0x4e800020          -- blr
-         ]
-
-#elif powerpc_TARGET_ARCH && linux_TARGET_OS
-
-   -- All offsets here are measured in Words (not bytes).  This includes
-   -- arguments to the load/store machine code generators, alignment numbers
-   -- and the final 'framesize' among others.
-
-   = concatMap w32_to_w8s_bigEndian $ [
-            0x7c0802a6,                         -- mflr r0
-            0x93e1fffc,                         -- stw r31,-4(r1)
-            0x90010008,                         -- stw r0,8(r1)
-            0x94210000 .|. offset (-framesize), -- stwu r1, -frameSize(r1)
-            0x7c7f1b78                          -- mr r31, r3
-            ] ++ pass_parameters ++             -- pass the parameters
-            loadWord 12 addr_offW ++ [          -- lwz r12, a_off(r31)
-            0x7d8903a6,                         -- mtctr r12
-            0x4e800421                          -- bctrl
-            ] ++ gather_result ++ [             -- save the return value
-            0x80210000,                         -- lwz r1, 0(r1)
-            0x83e1fffc,                         -- lwz r31, -4(r1)
-            0x80010008,                         -- lwz r0, 8(r1)
-            0x7c0803a6,                         -- mtlr r0
-            0x4e800020                          -- blr
-         ]
-
-   where
-     gather_result :: [Word32]
-     gather_result = case r_rep of
-       VoidRep   -> []
-       FloatRep  -> storeFloat  1 r_offW
-       DoubleRep -> storeDouble 1 r_offW
-       Int64Rep  -> storeLong   3 r_offW
-       Word64Rep -> storeLong   3 r_offW
-       _         -> storeWord   3 r_offW
-
-     pass_parameters :: [Word32]
-     pass_parameters = concat params
-
-     -- vector aligned (4 word = 16 bytes) with 8 extra words of buffer space
-     framesize = alignedTo 4 (argsize + 8)
-
-     ((_,_,argsize), params) = mapAccumL loadparam (3,1,2) arg_offs_n_reps
-
-     -- handle one argument, returning machine code and the updated state
-     loadparam :: (Int, Int, Int) -> (Int, PrimRep) ->
-                  ((Int, Int, Int), [Word32])
-
-     loadparam (gpr, fpr, stack) (ofs, rep) = case rep of
-       FloatRep | fpr <= 8  -> ( (gpr, fpr + 1, stack),  loadFloat fpr ofs )
-       FloatRep             -> ( (gpr, fpr, stack + 1),  stackWord stack ofs )
-
-       DoubleRep | fpr <= 8 -> ( (gpr, fpr + 1, stack),  loadDouble fpr ofs )
-       DoubleRep            -> ( (gpr, fpr, astack + 2), stackLong astack ofs )
-
-       r | is64 r && even gpr  -> loadparam (gpr + 1, fpr, stack) (ofs, rep)
-       r | is64 r && gpr <= 9  -> ( (gpr + 2, fpr, stack),  loadLong gpr ofs )
-       r | is64 r              -> ( (gpr, fpr, astack + 2), stackLong astack ofs )
-       _ | gpr <= 10        -> ( (gpr + 1, fpr, stack),  loadWord gpr ofs )
-       _                    -> ( (gpr, fpr, stack + 1),  stackWord stack ofs )
-      where astack = alignedTo 2 stack
-
-            is64 Int64Rep = True
-            is64 Word64Rep = True
-            is64 _ = False
-
-     alignedTo :: Int -> Int -> Int
-     alignedTo alignment x = case x `mod` alignment of
-                               0 -> x
-                               y -> x - y + alignment
-
-     -- convenience macros to do multiple-instruction data moves
-     stackWord dst src = loadWord 0 src ++ storeWordC 0 dst
-     stackLong dst src = stackWord dst src ++ stackWord (dst + 1) (src + 1)
-     loadLong  dst src = loadWord dst src ++ loadWord (dst + 1) (src + 1)
-     storeLong dst src = storeWord dst src ++ storeWord (dst + 1) (src + 1)
-
-     -- load data from the Haskell stack (relative to r31)
-     loadFloat   = loadstoreInstr 0xc01f0000 -- lfs fpr, ofs(r31)
-     loadDouble  = loadstoreInstr 0xc81f0000 -- lfd fpr, ofs(r31)
-     loadWord    = loadstoreInstr 0x801f0000 -- lwz gpr, ofs(r31)
-
-     -- store data to the Haskell stack (relative to r31)
-     storeFloat  = loadstoreInstr 0xd01f0000 -- stfs fpr, ofs(r31)
-     storeDouble = loadstoreInstr 0xd81f0000 -- stfd fpr, ofs(r31)
-     storeWord   = loadstoreInstr 0x901f0000 -- stw gpr, ofs(r31)
-
-     -- store data to the C stack (relative to r1)
-     storeWordC  = loadstoreInstr 0x90010000 -- stw gpr, ofs(r1)
-
-     -- machine code building blocks
-     loadstoreInstr :: Word32 -> Int -> Int -> [Word32]
-     loadstoreInstr code reg ofs = [ code .|. register reg .|. offset ofs ]
-
-     register :: Int -> Word32
-     register reg = fromIntegral reg `shiftL` 21
-
-     offset :: Int -> Word32
-     offset ofs   = fromIntegral (ofs * 4) .&. 0xFFFF
-
-     -- speaks for itself
-     w32_to_w8s_bigEndian :: Word32 -> [Word8]
-     w32_to_w8s_bigEndian w =  [fromIntegral (0xFF .&. (w `shiftR` 24)),
-                                fromIntegral (0xFF .&. (w `shiftR` 16)),
-                                fromIntegral (0xFF .&. (w `shiftR` 8)),
-                                fromIntegral (0xFF .&. w)]
-
-#else 
-
-   = throwDyn (InstallationError "foreign import is not implemented for GHCi on this platform.")
-
-#endif
-
-#if i386_TARGET_ARCH || x86_64_TARGET_ARCH
-lit32 :: Int -> [Word8]
-lit32 i = let w32 = (fromIntegral i) :: Word32
-          in  map (fromIntegral . ( .&. 0xFF))
-                  [w32, w32 `shiftR` 8, 
-                   w32 `shiftR` 16,  w32 `shiftR` 24]
-#endif
-
-#endif /* !USE_LIBFFI */
-
 moan64 :: String -> SDoc -> a
 moan64 msg pp_rep
    = unsafePerformIO (
 moan64 :: String -> SDoc -> a
 moan64 msg pp_rep
    = unsafePerformIO (
index 2e0079e..007f3eb 100644 (file)
@@ -21,9 +21,7 @@ import ByteCodeItbls
 import ByteCodeAsm
 import ByteCodeLink
 import ByteCodeFFI
 import ByteCodeAsm
 import ByteCodeLink
 import ByteCodeFFI
-#ifdef USE_LIBFFI
 import LibFFI
 import LibFFI
-#endif
 
 import Outputable
 import Name
 
 import Outputable
 import Name
@@ -1063,19 +1061,11 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
         stk_offset   = d_after_r - s
 
      -- in
         stk_offset   = d_after_r - s
 
      -- in
-#if !defined(USE_LIBFFI)
-     -- In the native case, we build marshalling code and attach the
-     -- address of that to the CCALL instruction
-     addr_of_marshaller <- ioToBc (mkMarshalCode cconv
-                                (r_offW, r_rep) addr_offW
-                                (zip args_offW a_reps))
-#else
      -- the only difference in libffi mode is that we prepare a cif
      -- describing the call type by calling libffi, and we attach the
      -- address of this to the CCALL instruction.
      token <- ioToBc $ prepForeignCall cconv a_reps r_rep
      let addr_of_marshaller = castPtrToFunPtr token
      -- the only difference in libffi mode is that we prepare a cif
      -- describing the call type by calling libffi, and we attach the
      -- address of this to the CCALL instruction.
      token <- ioToBc $ prepForeignCall cconv a_reps r_rep
      let addr_of_marshaller = castPtrToFunPtr token
-#endif
 
      recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller))
      let
 
      recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller))
      let
index 3708238..7f24d01 100644 (file)
@@ -6,12 +6,6 @@
 --
 -----------------------------------------------------------------------------
 
 --
 -----------------------------------------------------------------------------
 
-#ifndef USE_LIBFFI
-
-module LibFFI () where
-
-#else
-
 #include <ffi.h>
 
 module LibFFI (
 #include <ffi.h>
 
 module LibFFI (
@@ -142,5 +136,3 @@ foreign import ccall "ffi_prep_cif"
 --            -> Ptr ()                    -- put result here
 --            -> Ptr (Ptr ())              -- arg values
 --            -> IO ()
 --            -> Ptr ()                    -- put result here
 --            -> Ptr (Ptr ())              -- arg values
 --            -> IO ()
-
-#endif
diff --git a/libffi/Makefile b/libffi/Makefile
new file mode 100644 (file)
index 0000000..3a7cb69
--- /dev/null
@@ -0,0 +1,124 @@
+
+TOP=..
+
+include $(TOP)/mk/boilerplate.mk
+
+# -----------------------------------------------------------------------------
+# This Makefile is copied from the one we use for GMP in ../gmp.
+#
+# We use libffi's own configuration stuff.
+
+PLATFORM := $(shell echo $(HOSTPLATFORM) | sed 's/i[567]86/i486/g')
+
+# 2007-09-26
+#     set -o igncr 
+# is not a valid command on non-Cygwin-systems.
+# Let it fail silently instead of aborting the build.
+#
+# 2007-07-05
+# We do
+#     set -o igncr; export SHELLOPTS
+# here as otherwise checking the size of limbs
+# makes the build fall over on Cygwin. See the thread
+# http://www.cygwin.com/ml/cygwin/2006-12/msg00011.html
+# for more details.
+
+# 2007-07-05
+# Passing
+#     as_ln_s='cp -p'
+# isn't sufficient to stop cygwin using symlinks the mingw gcc can't
+# follow, as it isn't used consistently. Instead we put an ln.bat in
+# path that always fails.
+
+LIBFFI_TARBALL := $(firstword $(wildcard libffi*.tar.gz))
+LIBFFI_DIR := $(subst .tar.gz,,$(LIBFFI_TARBALL))
+
+ifeq "$(findstring dyn, $(GhcRTSWays))" "dyn"
+BUILD_SHARED=yes
+else
+BUILD_SHARED=no
+endif
+
+boot :: stamp.ffi.static
+BINDIST_STAMPS = stamp.ffi.static
+INSTALL_HEADERS += ffi.h
+INSTALL_LIBS += libffi.a
+
+ifeq "$(BUILD_SHARED)" "yes"
+boot :: stamp.ffi.shared
+BINDIST_STAMPS += stamp.ffi.shared
+INSTALL_LIBS += libffi.dll.a
+INSTALL_PROGS += libffi-3.dll
+endif
+
+install all :: $(INSTALL_HEADERS) $(INSTALL_LIBS) $(INSTALL_PROGS)
+
+stamp.ffi.static:
+       $(RM) -rf $(LIBFFI_DIR) build
+       $(TAR) -zxf $(LIBFFI_TARBALL)
+       mv $(LIBFFI_DIR) build
+#      chmod +x ln
+       (set -o igncr 2>/dev/null) && set -o igncr; export SHELLOPTS; \
+           PATH=`pwd`:$$PATH; \
+           export PATH; \
+           cd build && \
+           CC=$(WhatGccIsCalled) $(SHELL) configure \
+                 --enable-shared=no --host=$(PLATFORM) --build=$(PLATFORM)
+       touch $@
+
+stamp.ffi.shared:
+       $(RM) -rf $(LIBFFI_DIR) build-shared
+       $(TAR) -zxf $(LIBFFI_TARBALL)
+       mv $(LIBFFI_DIR) build-shared
+#      chmod +x ln
+       (set -o igncr 2>/dev/null) && set -o igncr; export SHELLOPTS; \
+           PATH=`pwd`:$$PATH; \
+           export PATH; \
+           cd build-shared && \
+           CC=$(WhatGccIsCalled) $(SHELL) configure \
+                 --enable-shared=yes --disable-static --host=$(PLATFORM) --build=$(PLATFORM)
+       touch $@
+
+ffi.h: stamp.ffi.static
+       $(CP) build/include/ffi.h .
+
+libffi.a: stamp.ffi.static
+       $(MAKE) -C build MAKEFLAGS=
+       $(CP) build/.libs/libffi.a .
+       $(RANLIB) libffi.a
+
+libffi-3.dll: stamp.ffi.shared
+       $(MAKE) -C build-shared MAKEFLAGS=
+       $(CP) build-shared/.libs/libffi-3.dll .
+
+libffi.dll.a: libffi-3.dll
+       $(CP) build-shared/.libs/libffi.dll.a .
+
+clean distclean maintainer-clean ::
+       $(RM) -f stamp.ffi.static stamp.ffi.shared ffi.h
+       $(RM) -f libffi.a libffi-3.dll libffi.dll.a
+       $(RM) -rf build
+       $(RM) -rf build-shared
+
+#-----------------------------------------------------------------------------
+#
+# binary-dist
+
+include $(TOP)/mk/target.mk
+
+binary-dist:
+       $(INSTALL_DIR)                         $(BIN_DIST_DIR)/libffi
+       $(INSTALL_DATA)    Makefile            $(BIN_DIST_DIR)/libffi/
+ifneq "$(HaveLibFFI)" "YES"
+       $(INSTALL_DATA)    $(BINDIST_STAMPS)   $(BIN_DIST_DIR)/libffi/
+  ifneq "$(INSTALL_PROGS)" ""
+       $(INSTALL_DATA)    $(INSTALL_PROGS)    $(BIN_DIST_DIR)/libffi/
+  endif
+  ifneq "$(INSTALL_LIBS)" ""
+       $(INSTALL_DATA)    $(INSTALL_LIBS)     $(BIN_DIST_DIR)/libffi/
+  endif
+  ifneq "$(INSTALL_HEADERS)" ""
+       $(INSTALL_HEADER)  $(INSTALL_HEADERS)  $(BIN_DIST_DIR)/libffi/
+  endif
+endif
+
diff --git a/libffi/libffi-3.0.4.tar.gz b/libffi/libffi-3.0.4.tar.gz
new file mode 100644 (file)
index 0000000..0b20310
Binary files /dev/null and b/libffi/libffi-3.0.4.tar.gz differ
index 8c38df6..40bc9dd 100644 (file)
@@ -42,9 +42,9 @@ Haskell side.
 #include "RtsUtils.h"
 #include <stdlib.h>
 
 #include "RtsUtils.h"
 #include <stdlib.h>
 
-#if defined(USE_LIBFFI)
+#if defined(USE_LIBFFI_FOR_ADJUSTORS)
 
 
-#include <ffi.h>
+#include "ffi.h"
 #include <string.h>
 
 void
 #include <string.h>
 
 void
@@ -1172,4 +1172,4 @@ if ( *(unsigned char*)ptr != 0xe8 ) {
  freeExec(ptr);
 }
 
  freeExec(ptr);
 }
 
-#endif // !USE_LIBFFI
+#endif // !USE_LIBFFI_FOR_ADJUSTORS
index 3962856..ab59533 100644 (file)
@@ -28,9 +28,7 @@
 #include <errno.h>
 #endif
 
 #include <errno.h>
 #endif
 
-#ifdef USE_LIBFFI
-#include <ffi.h>
-#endif
+#include "ffi.h"
 
 /* --------------------------------------------------------------------------
  * The bytecode interpreter
 
 /* --------------------------------------------------------------------------
  * The bytecode interpreter
@@ -1347,7 +1345,6 @@ run_BCO:
                So we make a copy of the argument block.
             */
 
                So we make a copy of the argument block.
             */
 
-#ifdef USE_LIBFFI
 #define ROUND_UP_WDS(p)  ((((StgWord)(p)) + sizeof(W_)-1)/sizeof(W_))
 
             ffi_cif *cif = (ffi_cif *)marshall_fn;
 #define ROUND_UP_WDS(p)  ((((StgWord)(p)) + sizeof(W_)-1)/sizeof(W_))
 
             ffi_cif *cif = (ffi_cif *)marshall_fn;
@@ -1384,10 +1381,6 @@ run_BCO:
 
             // this is the function we're going to call
             fn = (void(*)(void))Sp[ret_size];
 
             // this is the function we're going to call
             fn = (void(*)(void))Sp[ret_size];
-#else
-           W_ arguments[stk_offset];
-           memcpy(arguments, Sp, sizeof(W_) * stk_offset);
-#endif
 
            // Restore the Haskell thread's current value of errno
            errno = cap->r.rCurrentTSO->saved_errno;
 
            // Restore the Haskell thread's current value of errno
            errno = cap->r.rCurrentTSO->saved_errno;
@@ -1415,11 +1408,7 @@ run_BCO:
            tok = suspendThread(&cap->r);
 
            // We already made a copy of the arguments above.
            tok = suspendThread(&cap->r);
 
            // We already made a copy of the arguments above.
-#ifdef USE_LIBFFI
             ffi_call(cif, fn, ret, argptrs);
             ffi_call(cif, fn, ret, argptrs);
-#else
-           marshall_fn ( arguments );
-#endif
 
            // And restart the thread again, popping the RET_DYN frame.
            cap = (Capability *)((void *)((unsigned char*)resumeThread(tok) - sizeof(StgFunTable)));
 
            // And restart the thread again, popping the RET_DYN frame.
            cap = (Capability *)((void *)((unsigned char*)resumeThread(tok) - sizeof(StgFunTable)));
@@ -1441,11 +1430,7 @@ run_BCO:
                
            // Copy the return value back to the TSO stack.  It is at
             // most 2 words large, and resides at arguments[0].
                
            // Copy the return value back to the TSO stack.  It is at
             // most 2 words large, and resides at arguments[0].
-#ifdef USE_LIBFFI
             memcpy(Sp, ret, sizeof(W_) * stg_min(stk_offset,ret_size));
             memcpy(Sp, ret, sizeof(W_) * stg_min(stk_offset,ret_size));
-#else
-           memcpy(Sp, arguments, sizeof(W_) * stg_min(stk_offset,2));
-#endif
 
            goto nextInsn;
        }
 
            goto nextInsn;
        }
index 59143b9..b193f01 100644 (file)
@@ -441,6 +441,22 @@ typedef struct _RtsSymbolVal {
    SymX(console_handler)
 #endif
 
    SymX(console_handler)
 #endif
 
+#define RTS_LIBFFI_SYMBOLS                      \
+     Sym(ffi_prep_cif)                          \
+     Sym(ffi_call)                              \
+     Sym(ffi_type_void)                         \
+     Sym(ffi_type_float)                        \
+     Sym(ffi_type_double)                       \
+     Sym(ffi_type_sint64)                       \
+     Sym(ffi_type_uint64)                       \
+     Sym(ffi_type_sint32)                       \
+     Sym(ffi_type_uint32)                       \
+     Sym(ffi_type_sint16)                       \
+     Sym(ffi_type_uint16)                       \
+     Sym(ffi_type_sint8)                        \
+     Sym(ffi_type_uint8)                        \
+     Sym(ffi_type_pointer)
+
 #ifdef TABLES_NEXT_TO_CODE
 #define RTS_RET_SYMBOLS /* nothing */
 #else
 #ifdef TABLES_NEXT_TO_CODE
 #define RTS_RET_SYMBOLS /* nothing */
 #else
@@ -828,6 +844,7 @@ RTS_MINGW_ONLY_SYMBOLS
 RTS_CYGWIN_ONLY_SYMBOLS
 RTS_DARWIN_ONLY_SYMBOLS
 RTS_LIBGCC_SYMBOLS
 RTS_CYGWIN_ONLY_SYMBOLS
 RTS_DARWIN_ONLY_SYMBOLS
 RTS_LIBGCC_SYMBOLS
+RTS_LIBFFI_SYMBOLS
 #undef Sym
 #undef SymX
 #undef SymX_redirect
 #undef Sym
 #undef SymX
 #undef SymX_redirect
@@ -860,6 +877,7 @@ static RtsSymbolVal rtsSyms[] = {
       RTS_CYGWIN_ONLY_SYMBOLS
       RTS_DARWIN_ONLY_SYMBOLS
       RTS_LIBGCC_SYMBOLS
       RTS_CYGWIN_ONLY_SYMBOLS
       RTS_DARWIN_ONLY_SYMBOLS
       RTS_LIBGCC_SYMBOLS
+      RTS_LIBFFI_SYMBOLS
 #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
       // dyld stub code contains references to this,
       // but it should never be called because we treat
 #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
       // dyld stub code contains references to this,
       // but it should never be called because we treat
index 6fb1688..516879a 100644 (file)
@@ -159,9 +159,8 @@ SRC_CC_OPTS += -DNOSMP
 SRC_HC_OPTS += -optc-DNOSMP
 endif
 
 SRC_HC_OPTS += -optc-DNOSMP
 endif
 
-ifeq "$(UseLibFFI)" "YES"
-SRC_CC_OPTS += -DUSE_LIBFFI
-PACKAGE_CPP_OPTS += -DUSE_LIBFFI
+ifeq "$(UseLibFFIForAdjustors)" "YES"
+SRC_CC_OPTS += -DUSE_LIBFFI_FOR_ADJUSTORS
 endif
 
 ifneq "$(DYNAMIC_RTS)" "YES"
 endif
 
 ifneq "$(DYNAMIC_RTS)" "YES"
@@ -202,6 +201,9 @@ RtsUtils_CC_OPTS += -DTargetPlatform=$(DQ)$(TARGETPLATFORM)$(DQ)
 RtsUtils_CC_OPTS += -DGhcUnregisterised=$(DQ)$(GhcUnregisterised)$(DQ)
 RtsUtils_CC_OPTS += -DGhcEnableTablesNextToCode=$(DQ)$(GhcEnableTablesNextToCode)$(DQ)
 
 RtsUtils_CC_OPTS += -DGhcUnregisterised=$(DQ)$(GhcUnregisterised)$(DQ)
 RtsUtils_CC_OPTS += -DGhcEnableTablesNextToCode=$(DQ)$(GhcEnableTablesNextToCode)$(DQ)
 
+# ffi.h triggers prototype warnings, so disable them here:
+Interpreter_CC_OPTS += -Wno-strict-prototypes
+
 StgCRun_CC_OPTS += -w
 Typeable_CC_OPTS += -w
 RetainerProfile_CC_OPTS += -w
 StgCRun_CC_OPTS += -w
 Typeable_CC_OPTS += -w
 RetainerProfile_CC_OPTS += -w
@@ -312,12 +314,6 @@ CLEAN_FILES += $(AUTO_APPLY_CMM)
 endif
 
 # -----------------------------------------------------------------------------
 endif
 
 # -----------------------------------------------------------------------------
-# Compile GMP only if we don't have it already
-#
-# We use GMP's own configuration stuff, because it's all rather hairy
-# and not worth re-implementing in our Makefile framework.
-
-CLEAN_FILES += gmp/libgmp.a
 
 # Need to get the GMP vars in through CPP to package.conf.in, and put
 # quotes around each element.
 
 # Need to get the GMP vars in through CPP to package.conf.in, and put
 # quotes around each element.
@@ -343,6 +339,14 @@ SRC_HSC2HS_OPTS += -I../gmp/gmpbuild
 SRC_LD_OPTS += -L../gmp/gmpbuild
 
 #-----------------------------------------------------------------------------
 SRC_LD_OPTS += -L../gmp/gmpbuild
 
 #-----------------------------------------------------------------------------
+# libffi stuff
+
+SRC_CC_OPTS     += -I../libffi/build/include
+SRC_HC_OPTS     += -I../libffi/build/include
+SRC_HSC2HS_OPTS += -I../libffi/build/include
+SRC_LD_OPTS     += -L../libffi/build/include
+
+#-----------------------------------------------------------------------------
 #
 # Building the GUM SysMan
 #
 #
 # Building the GUM SysMan
 #
@@ -429,7 +433,6 @@ endif
 
 binary-dist:
        $(INSTALL_DIR)                         $(BIN_DIST_DIR)/rts
 
 binary-dist:
        $(INSTALL_DIR)                         $(BIN_DIST_DIR)/rts
-       $(INSTALL_DIR)                         $(BIN_DIST_DIR)/rts/gmp
        $(INSTALL_DATA)    Makefile            $(BIN_DIST_DIR)/rts/
        $(INSTALL_DATA)    package.conf.in     $(BIN_DIST_DIR)/rts/
 ifneq "$(INSTALL_LIBS)" ""
        $(INSTALL_DATA)    Makefile            $(BIN_DIST_DIR)/rts/
        $(INSTALL_DATA)    package.conf.in     $(BIN_DIST_DIR)/rts/
 ifneq "$(INSTALL_LIBS)" ""
index 1642101..7e0ee02 100644 (file)
@@ -25,11 +25,13 @@ library-dirs:               FPTOOLS_TOP_ABS"/rts" GMP_LIB_DIRS
 # if !defined(HAVE_LIBGMP) && !defined(HAVE_FRAMEWORK_GMP)
                        , FPTOOLS_TOP_ABS"/gmp"
 # endif
 # if !defined(HAVE_LIBGMP) && !defined(HAVE_FRAMEWORK_GMP)
                        , FPTOOLS_TOP_ABS"/gmp"
 # endif
+                        , FPTOOLS_TOP_ABS"/libffi"
 #endif
 
 hs-libraries:   "HSrts"
 
 extra-libraries:               "m"             /* for ldexp() */
 #endif
 
 hs-libraries:   "HSrts"
 
 extra-libraries:               "m"             /* for ldexp() */
+                             , "ffi"
 #ifndef HAVE_FRAMEWORK_GMP
                              , "gmp"
 #ifdef HAVE_LIBDL
 #ifndef HAVE_FRAMEWORK_GMP
                              , "gmp"
 #ifdef HAVE_LIBDL
@@ -56,9 +58,6 @@ extra-libraries:              "m"             /* for ldexp() */
 #if USE_PAPI
                             , "papi"
 #endif
 #if USE_PAPI
                             , "papi"
 #endif
-#ifdef USE_LIBFFI
-                             , "ffi"
-#endif
 
 #ifdef INSTALLING
 include-dirs:          INCLUDE_DIR GMP_INCLUDE_DIRS
 
 #ifdef INSTALLING
 include-dirs:          INCLUDE_DIR GMP_INCLUDE_DIRS