[Haskell-cafe] question re: FFI and ensuring unwrapped values are present on stack

Charles Strahan charles.c.strahan at gmail.com
Mon Mar 3 05:41:13 UTC 2014


Hello all,

This is probably going to be a pretty niche question, but I'm hoping
someone here can lend a hand.

I'm working on a binding for the YARV Ruby VM, and I'm struggling to come
up a with a good interop story with respect to its GC implementation. I
have two options to prevent premature GC of Ruby object pointers:

1) Guarantee that the pointers reside on the stack or in registers,
2) or copy the pointer itself to another static area of memory and register
that address with the GC.

So, the big question is: is there a way to make #1 a reality, while
operating in the IO monad?

I can picture something like the following:

newtype RValue = RValue (Ptr RValue) deriving (Storable)

withObject :: IO RValue         -- e.g. result of some ccall, or some
further transformation thereof
           -> (RValue -> IO a)  -- the RValue is now on the stack (or in a
register), available for use without worry of premature GC
           -> IO a              -- the result of computation

With Haskell being a non-strict language, I understand that there are a lot
of instances where a value could end up on the heap, with a thunk being
passed via stack/registers. For my needs, I'd need some way to guarantee
that the RValues being passed to and from withObject are at all times kept
unwrapped and off the heap, and likewise within the second argument.

Given my rather limited knowledge of Haskell (I've been programming in
Haskell for about a month now), I think the best I can come up with is the
second option suggested above:

withObject :: (Ptr RValue -> IO ()) -- e.g. void some_fun(VALUE* out) {...}
           -> (RValue -> IO a)      -- e.g. do something with `out` derefed
           -> IO a
withObject f g =
    alloca $ \ptr -> do
        rb_gc_register_address ptr   -- prevent GC
        f ptr                        -- call wrapped native function
        val <- peek ptr              -- deref the VALUE*
        res <- g val                 -- pass to function
        rb_gc_unregister_address ptr -- clean up
        res

So, while the above would work, it's really, really ugly (IMO). That, and
I'd have to wrap all the native functions so that instead of returning
VALUE, they'd write to some out ptr and return void. And there's the
otherwise unnecessary alloca.

I hope that was clear enough - any advice would be super duper appreciated!

I'm assuming that there isn't a way I can get away with using the typical
monadic bind syntax while keeping the RValues off the heap; if I'm wrong,
and I can skip the whole withObject/HOF approach, I'd love to know it! I'm
not (yet) familiar enough with the compiler / language spec to know about
such guarantees, should they exist...

- Charles
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140303/28e62b38/attachment.html>


More information about the Haskell-Cafe mailing list