FFI: c/c++ struct on stack as an argument or return value

Edward Kmett ekmett at gmail.com
Fri Mar 14 19:01:52 UTC 2014


On Fri, Mar 14, 2014 at 2:00 PM, Yuras Shumovich <shumovichy at gmail.com>wrote:

> On Fri, 2014-03-14 at 09:08 -0400, Edward Kmett wrote:
> > I spent some time hacking around on this from a library perspective when
> I
> > had to interoperate with a bunch of Objective C on a 64-bit mac as many
> of
> > the core library functions you need to FFI out to pass around pairs of
> Int32s
> > as a struct small enough by the x64 ABI to get shoehorned into one
> > register, and as I was programmatically cloning Objective C APIs via
> > template haskell I couldn't use the usual clunky C shims.
>
> Was it related to language-c-inline package?


It was an exercise in serial yak shaving brought about by writing a
realtime GPU-based Metropolis light transport raytracer... er.. nevermind.
=)

> So if nothing else, you can at least take this as a vote of confidence
> that
> > your idea isn't crazy. =)
> >
> > I'd also be happy to answer questions if you get stuck or need help.
>
> Thank you, Edward
>
> Since there is at least one person how is interested in, I'll start
> asking questions. Please let me know when I become too noisy :)
>
> For now I'm focused on desugaring phase. Right now
>
> type Fn = CInt -> CInt -> IO ()
> foreign import ccall "wrapper" f :: Fn -> IO (FunPtr Fn)
>
> is desugared into
>
> f :: Fn -> IO (FunPtr Fn)
> f hsFunc = do
>   sPtr <- newStablePtr hsFunc
>   createAdjustor sPtr staticWrapper ...
>
> Here staticWrapper -- address of C function. It will dereference the
> sPtr, cast to StgClosure* and call with appropriate arguments. All the
> arguments are primitive C types (int, char, pointer, etc), so it is easy
> to convert them to corresponding haskell types via rts_mkInt, rts_mkChar
> etc.
>
> But I want to allow argument to be C structs.
>
> data CStruct {
>   i :: CInt,
>   j :: CInt
> }
> type Fn = CStruct -> IO ()
> foreign import ccall "wrapper" f :: Fn -> IO (FunPtr Fn)
>
> Looks like it is impossible to instantiate CStruct from C function. Is
> it true? Is it easy to add such functionality?
>
> The only solution I see is to flatten CStruct before creating StablePtr:
>
> f :: Fn -> IO (FunPtr Fn)
> f hsFunc = do
>   sPtr <- newStablePtr $ \i j -> hsFunc (CStruct i j)
>   createAdjustor sPtr staticWrapper ...
>
> Does it make sense? It will add performance overhead because of
> additional indirection. Better ideas are welcome.
>

Not sure. This is a much lower level (and more correct .. and likely
faster) approach than I was taking.

I'd just built all my functions in a way that would cache the resulting
ffi_prep_cif for each signature using typeclass magic. I had to do some
allocations on each ffi_call though as well for struct avalues though, so
I'm guessing you'd have to do at least that much.





> Thanks,
> Yuras
>
> >
> > -Edward
> >
> >
> > On Fri, Mar 14, 2014 at 7:50 AM, Yuras Shumovich <shumovichy at gmail.com
> >wrote:
> >
> > >
> > > Hi,
> > >
> > > Right now ghc's FFI doesn't support c/c++ structures.
> > >
> > > Whenever we have foreign function that accepts or returns struct by
> > > value, we have to create wrapper that accepts or returns pointer to
> > > struct. It is inconvenient, but actually not a big deal.
> > >
> > > But there is no easy workaround when you want to export haskell
> function
> > > to use it with c/c++ API that requires structures to be passed by value
> > > (Usually it is a callback in c/c++ API. You can't change it's
> signature,
> > > and if it doesn't provide some kind of "void* userdata", then you are
> > > stuck.)
> > >
> > > I'm interested in fixing that. I'm going to start with 'foreign import
> > > "wrapper" ...' stuff.
> > >
> > > Calling conventions for passing c/c++ structures by value are pretty
> > > tricky and platform/compiler specific. So initially I'll use libffi for
> > > that (it will work when USE_LIBFFI_FOR_ADJUSTORS is defined, see
> > > rts/Adjustor.c). It will allow me to explore design space without
> > > bothering about low level implementation details. Later it could be
> > > implemented for native (non-libffi) adjustors.
> > >
> > > Is anybody interested it that? I appreciate any comments/ideas.
> > >
> > > Right now I don't have clear design. It would be nice to support plain
> > > haskell data types that are 1) not recursive, 2) has one constructor
> and
> > > 3) contains only c/c++ types. But it doesn't work with c/c++ unions.
> Any
> > > ideas are welcome.
> > >
> > > An example how to use libffi with structures:
> > > http://www.atmark-techno.com/~yashi/libffi.html#Structures
> > >
> > > Thanks,
> > > Yuras
> > >
> > >
> > > _______________________________________________
> > > ghc-devs mailing list
> > > ghc-devs at haskell.org
> > > http://www.haskell.org/mailman/listinfo/ghc-devs
> > >
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/ghc-devs/attachments/20140314/866509ae/attachment.html>


More information about the ghc-devs mailing list