[m-dev.] Re: Signature of generated JAVA methods
Fergus Henderson
fjh at cs.mu.OZ.AU
Tue Feb 19 23:52:40 AEDT 2002
On 19-Feb-2002, Holger Krug <hkrug at rationalizer.com> wrote:
> Following your last review messages I've got the impression, that the
> Java port of Mercury now is really in the main focus. That is fine !
Well, our summer student Michael Wybrow, who has been working on the
Java port, is finishing up next week. So this trend might not continue.
> Andree just now showed me his first generated Java code. As I
> understand his work up to now he achieved to remove all the hindrances
> from the Mercury compiler which "protect" the user from generated Java
> code. Having taken a look at the Java code and after discussion with
> Andree I have some questions concerning the signature of generated
> Java code.
>
> As I understand, Andree has to generate Code for `det' and `semidet'
> procedures, because the other determinisms will be transformed away by
> a HLDS transformation.
For `pragma foreign_proc', yes, that's correct.
And likewise for the Java equivalent of `pragma import'
(`pragma import' is currently C-specific. We should generalize
this work with other languages -- `pragma foreign_import'? --
but this is not yet implemented).
But for `pragma export' (which currently is also C-specific),
`nondet' or `multi' procedures are just not supported.
This is mainly because supporting this in the LLDS back-end is
a bit tricky.
> Andree proposed the following signatures for genereted Java procedures:
Do you mean these signatures should be used for Java procedures imported
to Mercury or exported from Mercury with the Java interface equivalents of
`pragma import' and `pragma export'?
> A) det/semidet: Object[] name(InType1 in1, .... , InTypen inn);
> In the `semidet' case the array of Objects forming the return
> value gets one additional output parameter of boolean type.
This matches the calling convention used by the Java code
that the current Mercury compiler generates.
Note that it's not strictly necessary that the generated code and
the foreign language interface use the same interface, since `pragma import'
and `pragma export' are implemented using forwarding procedures anyway.
Indeed, for the MLDS->C back-end and C interface, they don't, e.g. the
MLDS->C back-end uses "MR_Box" in some places where the C interface uses
"MR_Word" (this is mainly for backwards compatibility reasons).
But it would certainly be *nicer* if the convention used by the
foreign interface matched that used by the generated code.
> My first proposal after Andree's presentation was:
>
> B) det/semidet: Object[] name(InType1 in1, .... , InTypen inn);
> For the `semidet' determinism failure is indicated by returning `null'.
> (Whereas an empty number of output parameters is indicated by
> returning an empty array.)
This is a good idea. It is both more efficient and more natural
(for Java programmers) than `A'.
Unfortunately it is hard to make this work nicely given the current design
of the MLDS back-end, where we map HLDS->MLDS->Java, rather than going
directly from HLDS->Java. The trouble is that the information about
determinism is lost when converting HLDS->MLDS, but the conversion from
multiple outputs to an array happens when converting from MLDS->Java.
One possibility would be to map multiple outputs to an array
when converting HLDS->MLDS, if the target language doesn't support
multiple outputs. However, this would add more conditional code
to the HLDS->MLDS code generator. There's already some conditional
code there to handle --det-copy-out and --nondet-copy-out,
but this would make it even messier.
Another possibility would be for mlds_to_java.m to assume that
if the first parameter has type `mlds__native_bool_type', then
it is a semidet procedure, and the other output arguments are
guaranteed not to be needed if the first output argument has
the value `false'... but obviously this is not a very robust
assumption.
Another possibility would be to somehow modify the MLDS to represent
this explicitly.
> Following the approach taken in (A) and (B) I think the generated code
> should contain the construction of the array of output parameters on
> the users behalf, using a fixed name (e.g. `ret'). Andree told me,
> that he ask you already about the name of this array, so this seems to
> be on track. As a consequence of this, I deem, Andree should generate
> a `return ret;' statement at the end of the method body.
> Better than having a fixed name of the array of output parameters
> would be the use of the same names as in the Mercury signature of the
> foreign proc not only for input parameters but also for output
> parameters.
In a `pragma foreign_proc', the user's code should definitely refer
to the output variables by name, not as `ret[N]'.
Here's an example:
:- pred foo(int, float, int).
:- pragma foreign_proc(java, foo(X::in, Y::out, Z::out), "
/* this is the user's java code */
Y = X * 1.23;
Z = X + 42;
").
For this example, the Mercury compiler should either generate something
like this:
static object[] foo_1(int HeadVar__1) {
double HeadVar__2;
int HeadVar__3;
{
int X;
double Y;
int Z;
X = HeadVar__1;
/* this is the user's java code */
Y = X * 1.23;
Z = X + 42;
HeadVar__2 = Y;
HeadVar__3 = Z;
}
return new object[] { new java.lang.Double(HeadVar__2),
new java.lang.Integer(HeadVar__3) };
}
or like this:
static object[] foo_1(int HeadVar__1) {
double HeadVar__2;
int HeadVar__3;
object[] ret;
{
int X;
double Y;
int Z;
X = HeadVar__1;
/* this is the user's java code */
Y = X * 1.23;
Z = X + 42;
HeadVar__2 = Y;
HeadVar__3 = Z;
}
ret = new object[2];
ret[0] = new java.lang.Double(HeadVar__1);
ret[1] = new java.lang.Integer(HeadVar__2);
return ret;
}
But note that only the nested block
is generated from the `pragma foreign_proc' HLDS goal
(which becomes the `inline_target_code' MLDS statement).
The function declaration, the local variable declarations
at the top of the function body, and the return statement(s)
at the end will be generated from other parts of the HLDS/MLDS
by already-existing parts of the Mercury->MLDS->Java back-end.
Andre should not need to write any code to generate those parts.
> My questions now are:
>
> 1) Signatures (A), (B) or (C) or something different ?
I'd advise going with (A) for now.
> 2) In cases (A) and (B):
> 2.1) Generate the declaration `Object[] ret = new Object[NumOutParams];'
> 2.2) If 2.1 is answered by yes: what name to use for `ret'
> 2.3) If 2.1 is answered by yes: generate `return ret;' at the end of
> the body
This should be handled automatically by the existing code.
> 3) In the mid-term: Do you plan parsing embedded foreign language
> code or is this strictly excluded.
The Mercury compiler should be permitted to do so (and we currently do
so for `pragma foreign_type' in the .NET back-end), so it is not
strictly excluded, but the foreign language interface should be designed
so that this is never *necessary*.
> 4) What thoughts exist concerning debugging Java code ? Unfortunately the
> approach taken for C code (indicate the line numbers of the originial
> code to the preprocessor) does not work for Java.
Is there no equivalent to #line in Java?
If so, for the short term I'd say just debug the generated Java code.
In the long term, we should write mdb (trace/*) in Mercury rather than C.
But that is a very long-term project.
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list