new experimental "invoke-check" branch

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

new experimental "invoke-check" branch

Per Bothner
I created a new branch for the "invoke-invoke" rewrite.
If you're curious, you can grab it thus:

$ svn -q checkout svn://sourceware.org/svn/kawa/branches/invoke kawa-invoke

This currently requires MethodHandle, and hence won't work in Java 6
or Android.  That will be fixed before it is merged.

A lot of stuff works, including 'make check-r7rs' and
'make check-run-test-scripts'.  A lot of stuff doesn't work.
Both --full-tailcalls and --no-full-tailcalls work to some extent,
though the former has more problems.

The main idea is that for each function 'f' the compiler generates
a field 'f', a method 'f' (possibly more than one in the case of
#!optional parameters), and a method 'f$check'.  The latter is new,
and it replaces the argument-checking in the compiler-generated 'apply'
and 'check' methods.

The 'f$check' method is stored in the Procedure object, and called
using MethodHandle.invokeExact.  This should make slightly nicer
stack-traces, since you see 'f$check' rather than 'apply'.

There are actually two variations of 'f$check', depending on whether
it was compiled with --full-tailcalls.  These are similar, except for
how the return value is returned.  In fact argument-passing is now
the same for --full-tailcalls and --no-full-tailcalls, which is
very different from what it used to be.

A MethodHandle to 'f$check' is stored in the applyToObjectMethod field
of the 'f' Procedure object (stored in the 'f' field).  That is assuming
--no-full-tailcalls.  In the --full-tailcalls case 'f$check' is stored
in the Procedure.applyToConsumerMethod field.  Regardless, the "other"
field has a handle to a default method that calls 'f$check' and then
adjusts the result.

When the compiler sees a call to 'f', in the normal case it just
generates a call to the 'f' method, as before.  However, when calling
an unknown method, or doing a tail-call (and compiled with --full-tailcalls)
then things are very different.  It evaluates the arguments and saves them
in the values array of the CallContext object (using various convenience methods).
It does this without any specific knowledge of 'f'.  We then call the 'f$check'
routine.  This is currently always done indirectly, using Methodhandle.invokeExact:
In the --full-tailcalls case f$check' gets called in the CallContext.run trampoline.
Otherwise, when calling an invoke Procedure, we invoke Procedure.applyToObjectMethod.

The 'f$check' method does all the argument checking and then normally calls 'f' directly.
By default 'f$check' throws an exception on argument mismatch.  However, it can
be invoked with different flags to store an error code in the CallContext instead of
throwing the exception.  This is useful for multi-methods, where we want to try
multiple functions in turn until we find one that accepts the arguments.  (It is
also possible to call 'f$check' just to get an indication of whether the arguments
are ok, without actually calling 'f'.)

Keywords are now processed in the 'f$check' method which means you can select
between overloaded candidates based on matching keywords.  Keyword matching is
also more efficient, using a linear traversal.  (Or it least it will be:  I currently
sort the keyword list at run time, but the plan is to do so at compile-time.)

Keywords must now be literal in the argument list, but there will "apply-like"
functions to construct argument lists at runtime.  Typically this will use
the splicing operator '@LIST' rather than the apply method.  My current plan
is to have two splicing operators: '@LIST' (restricted to non-keywords; LIST
can be any sequence) and '@:ARGS' (a generalization that supports keywords).
There will be corresponding patterns in the formal-parameter list: @VAR and @:VAR.
The reason for two forms is for better error-checking and code-generation.

As hinted before: one of the goals of this work is to support patterns and guards
in the argument list.  These patterns will be checked in the 'f$check' method,
enabling pattern-based dispatch.

I hope to have this merged into the mainline in a small number of months,
but after the next Kawa release (which should be in a small number of weeks).
--
        --Per Bothner
[hidden email]   http://per.bothner.com/