In the Haskell2010 report, from section 8.4.2, there is a list of basic types that are supported in FFI import/export declarations:
The following types constitute the set of basic foreign types:
Char
,Int
,Double
,Float
, andBool
as exported by the Haskell Prelude as well asInt8
,Int16
,Int32
,Int64
,Word8
,Word16
,Word32
,Word64
,Ptr a
,FunPtr a
, andStablePtr a
, for any typea
, as exported by Foreign (Section 24).A Haskell system that implements the FFI needs to be able to pass these types between the Haskell and the external context as function arguments and results.
From the GHC manual section on extensions on FFI, GHC adds to these types with some unboxed types:
The following unboxed types may be used as basic foreign types (see FFI Addendum, Section 3.2):
Int#
,Word#
,Char#
,Float#
,Double#
,Addr#
,StablePtr# a
,MutableByteArray#
,ForeignObj#
, andByteArray#
.
It is pretty clear what happens for most of theses types at the level of the linker when i specify the ccall
calling convention. For example, I'm pretty sure Int
/Int#
get passed on the stack as two 32-bit values. Similarly, Ptr a
/StablePtr a
/StablePtr# a
/Addr#
probably all get passed as pointers on the stack.
What about ByteArray#
and MutableByteArray#
?
All I can imagine is passing them as pointers, but that seems a bit nuts since, unless you make your ByteArray#
/MutableByteArray#
pinned, the GHC runtime might end up moving the array from under you. Also, you would be ignoring the size information also on the array.