> I completely agree. Why not drop passing
> (Mutable)ByteArrays to foreign functions altogether - if a
> program wants to pass Haskell data to C land, the Right
> Thing is to use a StablePtr.
Agreed, if the call can re-enter the RTS.
> Now there maybe efficiency
> considerations when using this for marshaling purposes, but
> I think, what we really want here is a kind of Haskell
> variant of `alloca'.
>
> We want get a chunk of memory to which we can hand pointers
> over to C land - without having to worry whether the memory
> area potentially moves during a safe call. Furthermore, we
> want the lifetime of this block to be dependent on the live
> time of a function activation. The later is problematic due
> to tail calls.
You hit the nail on the head here. I was wondering how to implement the
lifetime restriction over a safe call, but there seems no easy way to do it.
When the call is of the form
case f(a,b,c) of
(# s, r #) -> ...
then we can easily enforce that a,b,c stay alive into the continuation, but
when the call is a tail-call we don't know what the continuation is. We
could translate all safe calls into the above form, but it's a bit
heavyweight if you'd prefer a tail-call.
GHC's storage manager has provision for allocating "unmovable" objects,
which are normally arrays and thread stacks. An unmovable object gets a
block to itself (blocks are currently 8k). So if we could solve the
lifetime problem, then this is at least a hack that will solve the mobility
problem.
> Actually, when the foreign call is a tail
> call, the memory area should live until we return from C
> land (in the current activation - not via a callback or so),
> but if the foreign call is no tail call, we want the memory
> area atually to live longer, as we may use it for out or
> inout parameter (like in C, where alloca memory lives as
> long as the function, in which it was allocated).
>
> I guess, everybody agrees that it won't be a good idea to
> put the burden of this lifetime decision on the compiler.
> So what remains are alloc/dealloc brackets for this kind of
> memory areas. And to make the implementation easier and
> because it doesn't really restrict the intended use, we
> should really enforce a stack discipline and use a wrapper
> function:
>
> alloca :: Int -> (Addr -> IO a) -> IO a
Nice idea. I'm not sure about the implementation though: did you have in
mind using C's malloc/free?
Cheers,
Simon