<div dir="ltr">Hello Adam,<div><br></div><div>Thanks for the suggestions! I considered ForeignPtrs+finalizers, but I'd like to avoid that due to weak guarantees you cite.</div><div><br></div><div>I do like the idea about using existentially quantified types to prevent leakage, and might give that more consideration (I can still see some use in allowing users to keep references to globals and such, granted they could just pull them out of the Ruby object graph again whenever they need a reference...).</div>
<div><br></div><div>However, I think I have arrived at a design I'm fairly happy with; I've written an 'RBIO' monad that's just a newtype wrapper around (StateT RValue IO a). Now, when the Ruby interpreter calls into my Haskell method definitions, it passes along an array which is then used as the state in my RBIO monad. Now, any other monadic interactions with the Ruby interpreter append the resulting object references to the array, and since the array is placed on Ruby's stack, all of those referenced objects get marked.</div>
<div><br></div><div>The end user API ends up looking something along the lines of:</div><div><br></div><div><div><font face="courier new, monospace"><div><div>newtype RValue = RValue (Ptr RValue) deriving (Eq, Ord, Show, Typeable, Data, Storable)</div>
<div>newtype RBIO a = RBIO { runRBIO :: StateT RValue IO a } deriving (Monad, MonadIO)</div></div><div><br></div><div>evalRBIO :: RValue -- array (used to prevent GC)</div><div>         -> RBIO a -- RBIO to eval</div><div>
         -> IO a</div></font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">defMethod :: RValue -- class</font></div><div><font face="courier new, monospace">          -> String -- method name</font></div>
<div><font face="courier new, monospace">          -> (RValue -> [RValue] -> Maybe RValue -> RBIO RValue) -- (self, args, block, result)</font></div><div><font face="courier new, monospace">          -> RBIO ()</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">rbCall :: RValue        -- self</font></div><div><font face="courier new, monospace">       -> String        -- method name</font></div>
<div><font face="courier new, monospace">       -> [RValue]      -- args</font></div><div><font face="courier new, monospace">       -> Maybe RValue  -- optional Ruby block/lambda</font></div><div><font face="courier new, monospace">       -> RBIO RValue</font></div>
</div><div><br></div><div>I'll follow up when I make the source available - so far, I think it's working out pretty well!</div><div><br></div><div>-Charles</div><div><br></div><div><br></div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Mon, Mar 3, 2014 at 6:17 PM, adam vogt <span dir="ltr"><<a href="mailto:vogt.adam@gmail.com" target="_blank">vogt.adam@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hello Charles,<br>
<br>
I don't know what can be done for your option 1, but I have two<br>
suggestions for your option 2:<br>
<br>
Did you consider making RValue a ForeignPtr and adding a FunPtr to<br>
rb_gc_unregister as the finalizer? That will end up being a bit less<br>
restrictive than your "withObject", in exchange for a weaker guarantee<br>
as to when the finalizer actually runs.<br>
<br>
Also you might use the same trick that <a href="http://Control.Monad.ST" target="_blank">Control.Monad.ST</a> does to<br>
prevent references from leaking out. In other words, change your<br>
definitions to look more like:<br>
<br>
newtype RValue s = RValue (ForeignPtr ())<br>
<br>
withObject :: (forall s. RValue s -> IO r)<br>
     -> IO r<br>
<br>
With that trick, (withObject return) becomes a type error.<br>
<br>
Regards,<br>
Adam<br>
<div><div class="h5"><br>
<br>
On Mon, Mar 3, 2014 at 12:41 AM, Charles Strahan<br>
<<a href="mailto:charles.c.strahan@gmail.com">charles.c.strahan@gmail.com</a>> wrote:<br>
> Hello all,<br>
><br>
> This is probably going to be a pretty niche question, but I'm hoping someone<br>
> here can lend a hand.<br>
><br>
> I'm working on a binding for the YARV Ruby VM, and I'm struggling to come up<br>
> a with a good interop story with respect to its GC implementation. I have<br>
> two options to prevent premature GC of Ruby object pointers:<br>
><br>
> 1) Guarantee that the pointers reside on the stack or in registers,<br>
> 2) or copy the pointer itself to another static area of memory and register<br>
> that address with the GC.<br>
><br>
> So, the big question is: is there a way to make #1 a reality, while<br>
> operating in the IO monad?<br>
><br>
> I can picture something like the following:<br>
><br>
> newtype RValue = RValue (Ptr RValue) deriving (Storable)<br>
><br>
> withObject :: IO RValue         -- e.g. result of some ccall, or some<br>
> further transformation thereof<br>
>            -> (RValue -> IO a)  -- the RValue is now on the stack (or in a<br>
> register), available for use without worry of premature GC<br>
>            -> IO a              -- the result of computation<br>
><br>
> With Haskell being a non-strict language, I understand that there are a lot<br>
> of instances where a value could end up on the heap, with a thunk being<br>
> passed via stack/registers. For my needs, I'd need some way to guarantee<br>
> that the RValues being passed to and from withObject are at all times kept<br>
> unwrapped and off the heap, and likewise within the second argument.<br>
><br>
> Given my rather limited knowledge of Haskell (I've been programming in<br>
> Haskell for about a month now), I think the best I can come up with is the<br>
> second option suggested above:<br>
><br>
> withObject :: (Ptr RValue -> IO ()) -- e.g. void some_fun(VALUE* out) {...}<br>
>            -> (RValue -> IO a)      -- e.g. do something with `out` derefed<br>
>            -> IO a<br>
> withObject f g =<br>
>     alloca $ \ptr -> do<br>
>         rb_gc_register_address ptr   -- prevent GC<br>
>         f ptr                        -- call wrapped native function<br>
>         val <- peek ptr              -- deref the VALUE*<br>
>         res <- g val                 -- pass to function<br>
>         rb_gc_unregister_address ptr -- clean up<br>
>         res<br>
><br>
> So, while the above would work, it's really, really ugly (IMO). That, and<br>
> I'd have to wrap all the native functions so that instead of returning<br>
> VALUE, they'd write to some out ptr and return void. And there's the<br>
> otherwise unnecessary alloca.<br>
><br>
> I hope that was clear enough - any advice would be super duper appreciated!<br>
><br>
> I'm assuming that there isn't a way I can get away with using the typical<br>
> monadic bind syntax while keeping the RValues off the heap; if I'm wrong,<br>
> and I can skip the whole withObject/HOF approach, I'd love to know it! I'm<br>
> not (yet) familiar enough with the compiler / language spec to know about<br>
> such guarantees, should they exist...<br>
><br>
> - Charles<br>
><br>
</div></div>> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
><br>
</blockquote></div><br></div>