Commit e0fcf61d authored by Simon Marlow's avatar Simon Marlow
Browse files

Import libffi-3.0.4, and use it to provide FFI support in GHCi

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).
parent 92986843
......@@ -67,12 +67,12 @@ include $(TOP)/mk/boilerplate.mk
# 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
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
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.
......
......@@ -308,7 +308,7 @@ else
@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)
......@@ -457,11 +457,6 @@ ALL_DIRS += javaGen
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
......@@ -517,6 +512,9 @@ ifeq "$(GhcDebugged)" "YES"
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,
......
This diff is collapsed.
......@@ -21,9 +21,7 @@ import ByteCodeItbls
import ByteCodeAsm
import ByteCodeLink
import ByteCodeFFI
#ifdef USE_LIBFFI
import LibFFI
#endif
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
#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
#endif
recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller))
let
......
......@@ -6,12 +6,6 @@
--
-----------------------------------------------------------------------------
#ifndef USE_LIBFFI
module LibFFI () where
#else
#include <ffi.h>
module LibFFI (
......@@ -142,5 +136,3 @@ foreign import ccall "ffi_prep_cif"
-- -> Ptr () -- put result here
-- -> Ptr (Ptr ()) -- arg values
-- -> IO ()
#endif
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
......@@ -42,9 +42,9 @@ Haskell side.
#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
......@@ -1172,4 +1172,4 @@ if ( *(unsigned char*)ptr != 0xe8 ) {
freeExec(ptr);
}
#endif // !USE_LIBFFI
#endif // !USE_LIBFFI_FOR_ADJUSTORS
......@@ -28,9 +28,7 @@
#include <errno.h>
#endif
#ifdef USE_LIBFFI
#include <ffi.h>
#endif
#include "ffi.h"
/* --------------------------------------------------------------------------
* The bytecode interpreter
......@@ -1347,7 +1345,6 @@ run_BCO:
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;
......@@ -1384,10 +1381,6 @@ run_BCO:
// 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;
......@@ -1415,11 +1408,7 @@ run_BCO:
tok = suspendThread(&cap->r);
// We already made a copy of the arguments above.
#ifdef USE_LIBFFI
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)));
......@@ -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].
#ifdef USE_LIBFFI
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;
}
......
......@@ -441,6 +441,22 @@ typedef struct _RtsSymbolVal {
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
......@@ -828,6 +844,7 @@ RTS_MINGW_ONLY_SYMBOLS
RTS_CYGWIN_ONLY_SYMBOLS
RTS_DARWIN_ONLY_SYMBOLS
RTS_LIBGCC_SYMBOLS
RTS_LIBFFI_SYMBOLS
#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_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
......
......@@ -159,9 +159,8 @@ SRC_CC_OPTS += -DNOSMP
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"
......@@ -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)
# 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
......@@ -312,12 +314,6 @@ CLEAN_FILES += $(AUTO_APPLY_CMM)
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.
......@@ -342,6 +338,14 @@ SRC_HC_OPTS += -I../gmp/gmpbuild
SRC_HSC2HS_OPTS += -I../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
......@@ -429,7 +433,6 @@ endif
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)" ""
......
......@@ -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
, FPTOOLS_TOP_ABS"/libffi"
#endif
hs-libraries: "HSrts"
extra-libraries: "m" /* for ldexp() */
, "ffi"
#ifndef HAVE_FRAMEWORK_GMP
, "gmp"
#ifdef HAVE_LIBDL
......@@ -56,9 +58,6 @@ extra-libraries: "m" /* for ldexp() */
#if USE_PAPI
, "papi"
#endif
#ifdef USE_LIBFFI
, "ffi"
#endif
#ifdef INSTALLING
include-dirs: INCLUDE_DIR GMP_INCLUDE_DIRS
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment