> 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

Reply via email to