[m-dev.] for discussion: proposed additions to FFI
Julien Fischer
juliensf at csse.unimelb.edu.au
Mon Jun 23 17:12:06 AEST 2008
This proposal extends the FFI with three new pragmas that allow for the
construction, deconstruction and testing of individual discriminated union
data constructors in foreign language code. The runtime already provides a
mechanism for doing this with the type list/1, e.g. the macros MR_list_head(),
MR_list_tail() and friends (defined in runtime/mercury_tags.h). It would be
nice to have something similar for arbitrary d.u. types - writing bindings to
foreign language libraries is the obvious application.
Unfortunately implementing the above macros by hand is fiddly - the are four
different implementations in runtime/mercury_tags.h that vary depending upon
the number of tag bits, number of reserved addresses etc. So rather than do
it by hand (which would be quite difficult for non-Mercury developers anyway) we
should get the compiler to do it.
All of the following can also be done using `pragma foreign_export' but that
has the disadvantage of being quite expensive, which is unfortunate you need
to call the exported procedure in the inner loop of a program. (This proposal
trades the safety of `pragma foreign_export' for improved runtime.)
An alternative to all of this would be to optimise exported procedures by
examining their bodies and generating specialised versions of the exported
procedure in the foreign language that could, for example, avoid saving the
state of the Mercury VM when that is not necessary. (My own opinion is that
we should do both.)
The proposed three new pragmas are:
:- pragma foreign_export_du_construction(<Lang>, <Type>, <Cons> <ForeignName>).
:- pragma foreign_export_du_deconstruction(<Lang>, <Type>, <Cons> <ForeignName>).
:- pragma foreign_export_du_test(<Lang>, <Type>, <Cons> <ForeignName>).
<Lang> is the foreign language.
<Type> is the name and arity of a Mercury discriminated union type.
<Cons> is the name and arity of a data constructor of type <Type>.
<ForeignName> is the name of a procedure## in language <Lang>.
## The meaning of "procedure" depends upon <Lang>. In C we would
almost certainly implement these as macros.
Some restrictions on them:
* The pragmas may only occur in the implementation section of a module.
* The same visibility restrictions with regard to `pragma foreign_export_enum'
(and its parameters) apply to them (and their parameters).
* construction/deconstruction foreign_export_du_ pragmas may not be used with
existentially quantified data constructors. (There's no real reason for this
restriction other than using such things would require more detailed
knowledge of the Mercury implementation, e.g. type_infos and
type_class_infos.)
* The data passing conventions apply as normal.
* They may be applied to enumerations although in that case the test and
deconstruction operations are identical.
Examples
--------
As an illustration the list operations in the runtime could be implemented as:
:- pragma foreign_export_du_construction("C", list/1, []/0, "MR_list_empty").
:- pragma foreign_export_du_test("C", list/1, [], "MR_list_is_empty").
:- pragma foreign_export_du_construction("C", list/1, [|]/2, "MR_list_cons").
(This could not be done in practice because doing so would introduce a
dependency between the standard library and the runtime.)
Another illustration, this time for the standard library's maybe/0 type:
:- pragma foreign_export_du_construction("C", maybe/0, yes/0, "ML_maybe_make_yes").
:- pragma foreign_export_du_construction("C", maybe/0, no/0, "ML_maybe_make_no").
:- pragma foreign_export_du_test("C", maybe/0, no/0, "ML_maybe_is_no").
:- pragma foreign_export_du_deconstruction("C", maybe/0, "ML_maybe_deconstruct_yes").
Semantics
---------
As with `pragma foreign_export_enum' and `pragma foreign_enum' the semantics
of these new pragmas depend upon the foreign language involved. We provide an
illustration for C here:
Note that <RepType> is the representation of type <Type> in <Lang> and
<FieldTypeK> is the representation type of the Kth field of data constructor <Cons>.
TEST:
:- pragma foreign_export_du_test("C", <Type>, <Cons>, <Name>).
causes the compiler to emit a procedure with the following signature:
MR_bool <Name>(<RepType> cons);
The procedure returns MR_TRUE if `cons' matches <Cons> and MR_FALSE otherwise.
CONSTRUCTION:
:- pragma foreign_export_du_construction("C", <Type>, <Cons>, <Name>).
causes the compiler to emit a procedure with the following signature:
<RepType> <Name>(<FieldType1> f1, ..., <FieldTypeN> fN);
Constructs a value of type <Type> corresponding to <Cons>. The arguments
give the values of each of the fields.
DECONSTRUCTION:
:- pragma foreign_export_du_deconstruction("C", <Type>, <Cons>, Name).
causes the compiler to emit a procedure with the following signature:
MR_bool <Name>(<RepType> cons, <FieldType1> *f1, ..., <FieldTypeN> *fN);
Returns MR_TRUE if `cons' matches <Cons> and sets the value of each of the
field arguments to the fields of `cons'. Returns MR_FALSE otherwise (in
which case the fields are not set.)
Notes
-----
The construction operations would be subject to the caveats mentioned in the
reference manual section ``Memory management for C''.
Julien.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at csse.unimelb.edu.au
Administrative Queries: owner-mercury-developers at csse.unimelb.edu.au
Subscriptions: mercury-developers-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the developers
mailing list