Something came up on the GHC list which made me realise that a slight
clarification is needed in the FFI spec. FinalizerPtr is defined as:
type FinalizerPtr a = FunPtr (Ptr a -> IO ())
However, there is no way to specify what the calling convention for a
FunPtr is. The calling convention is specified by the foreign import
declaration when calling one:
foreign import ccall "dynamic" foo ...
In the case of finalizers, the ForeignPtr implementation must pick a
calling convention to call the finalizer with. In GHC, we pick ccall.
This means that you can only use finalizers which expect the ccall
calling convention, something that isn't specified in the FFI addendum,
or the documentation for newForeignPtr.
What's the right thing to do here? The simple thing is just to document
the restriction, but that might be entirely wrong on systems that don't
support the ccall convention, for example. So perhaps there is a
per-platform fixed calling convention for finalizers.
Perhaps a FunPtr should remember its calling convention? But then what
is the calling convention for nullFunPtr, or the FunPtr returned by
castPtrToFunPtr?
Or perhaps we should have different versions of mkForeignPtr for each
calling convention? That doesn't sound too attractive either.
Cheers,
Simon