<div dir="ltr">Hello all,<div><br></div><div>This is probably going to be a pretty niche question, but I'm hoping someone here can lend a hand.</div><div><br></div><div>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:</div>
<div><br></div><div>1) Guarantee that the pointers reside on the stack or in registers,</div><div>2) or copy the pointer itself to another static area of memory and register that address with the GC.</div><div><br></div><div>
So, the big question is: is there a way to make #1 a reality, while operating in the IO monad?</div><div><br></div><div>I can picture something like the following:</div><div><br></div><div><div><font face="courier new, monospace">newtype RValue = RValue (Ptr RValue) deriving (Storable)</font></div>
<div><font face="courier new, monospace"><br></font></div><div><span style="font-family:'courier new',monospace">withObject :: IO RValue         -- e.g. result of some ccall, or some further transformation thereof</span><br>
</div></div><div><font face="courier new, monospace">           -> (RValue -> IO a)  -- the RValue is now on the stack (or in a register), available for use without worry of premature GC</font></div><div><font face="courier new, monospace">           -> IO a              -- the result of computation</font></div>
<div><br></div><div>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.</div>
<div><br></div><div>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:</div><div><br></div>
<div><div><font face="courier new, monospace">withObject :: (Ptr RValue -> IO ()) -- e.g. void some_fun(VALUE* out) {...}</font></div><div><font face="courier new, monospace">           -> (RValue -> IO a)      -- e.g. do something with `out` derefed</font></div>
<div><font face="courier new, monospace">           -> IO a</font></div><div><font face="courier new, monospace">withObject f g =</font></div><div><font face="courier new, monospace">    alloca $ \ptr -> do</font></div>
<div><font face="courier new, monospace">        rb_gc_register_address ptr   -- prevent GC</font></div><div><font face="courier new, monospace">        f ptr                        -- call wrapped native function</font></div>
<div><font face="courier new, monospace">        val <- peek ptr              -- deref the VALUE*</font></div><div><font face="courier new, monospace">        res <- g val                 -- pass to function</font></div>
<div><font face="courier new, monospace">        rb_gc_unregister_address ptr -- clean up</font></div><div><font face="courier new, monospace">        res</font></div><div><br></div></div><div>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.</div>
<div><br></div><div>I hope that was clear enough - any advice would be super duper appreciated!</div><div><br></div><div>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...</div>
<div><br></div><div>- Charles</div></div>