On 04/01/2016 21:51, David Matthews wrote:
On 04/01/2016 20:39, Phil Clayton wrote:
I've been looking at the new Foreign structure.  It is good to see that
the family of callNretM functions has been eliminated by introducing
cStar.  I've updated a few examples to use the buildCall<N> functions
and they appear to work.

With CInterface, I was avoiding the family of call<N> functions by
implementing a single call function based on call_sym or
call_sym_and_convert.  I am trying to do something equivalent using
Foreign.LowLevel based on the implementation in buildCall<N>withAbi.
There is a problem: the field "updateML" is not accessible because
   'a conversion
is abstract.  Am I right in thinking "updateML" is required for
conversions involving cStar?  If so, is there a way I can implement my
own variant of a buildCall function?

My thinking was that anyone programming at the level of Foreign.LowLevel
would want to build their own conversions.  I can see it's a problem if
you want to make use of the existing higher level conversions.

In case you're interested in an example of using the conversions, see the attached code. This defines a single 'call' function that avoids a family of 'call<N>' functions by taking a function signature that is constructed using existing conversions. For example:

   open Foreign Call
   val f1 = call sym1 (cInt && cInt --> cInt) : (int, int) pair -> int
   val f2 = call sym2 (cFloat --> cInt)       : real -> int
   ...
   ... f1 (2 & 3) : int
   ... f2 Math.e : int

Here, the existing conversions are convenient for capturing the characteristics of a C type even when not using the existing buildCall<N> functions. I don't have any objection to creating my own conversions - easily done by wrapping existing ones - it would just be nice if all the existing ones worked with the above.


Originally "conversion" was completely transparent but it meant that
constructing any new "conversion" required all the functions to be
provided even though most of the time the "update" functions aren't
needed.  I did think about having extended versions of "makeConversion"
and "breakConversion" which would allow the "update" functions to be
included or extracted.  I'd like to keep "conversion" abstract because I
can see that in the future it might be helpful to include extra
functions or fields and having it completely transparent makes it
difficult to provide backwards compatibility.

It take your point about abstraction. "updateML" and "updateC" seem reasonable in concept - they are variants of load and store that are applied to the arguments after a call - but perhaps their names could be more meaningful.

Hiding the "updateX" functions is not a problem for me. To avoid the family of callNretM functions in CInterface, I already have a framework in place for dealing with arguments passed by reference so I don't need to use "cStar", though it would have allowed a little more code to be shared with MLton. I could prevent "cStar" from being used accidentally by making my own conversion type.


Also - just an observation - in the functions buildCall<N>withAbi,
couldn't the argument offsets (and the amount of memory to malloc) be
calculated once, rather than for each foreign call?  E.g. in
buildCall2withAbi:

let
     val callF = callwithAbi abi [arg1Type, arg2Type] resType fnAddr
     val arg1Offset = alignUp(#size resType, #align arg1Type)
     val arg2Offset = alignUp(arg1Offset + #size arg1Type, #align
arg2Type)
     val argSize = arg2Offset + #size arg2Type
in
     fn (a, b) =>
     let
         val rMem = malloc argSize
         ...

True.  The idea is that these functions should all be inlined in which
case all these would be compile-time constants.  Making them inlined
means setting maxInlineSize to a very large value while compiling
"basis/Foreign.sml".  The way the basis library is compiled that wasn't
possible until the 5.6 compilers were built.

I'm trying to avoid making any changes in git "master" until the release
is complete but it would certainly be worth doing in the development
version.

Another observation for future consideration: there is no conversion for the boolean type. I believe that the existing CInterface.BOOL is a convenience for an int treated as a boolean (indicating a non-zero value) and can easily be created as a derived conversion. It's worth noting that C99 has a type "_Bool" (with a macro to refer to it as "bool") that "is large enough to store the values 0 and 1". Depending on the platform, I believe that sizeof(_Bool) could be larger than one byte, so it could be useful to have a conversion for the _Bool type.

Phil

Attachment: call.sml.gz
Description: GNU Zip compressed data

_______________________________________________
polyml mailing list
[email protected]
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to