MethodHandles for Kawa and other functional languages?
Rémi Forax
forax at univ-mlv.fr
Sun Oct 10 14:20:36 PDT 2010
Le 10/10/2010 20:08, Per Bothner a écrit :
> So we've determined that to make use of 292 Kawa should keep its
> abstract gnu.mapping.Procedure class, but add a new method:
> MethodHandle asMethodHandle()
>
> I mis-concluded that the compiler should therefore generate code
> to call asMethodHandle() and then the MethdHandle#invoke method.
> However, that doesn't seem like the right way to do it.
>
Why ?
> Instead, given a Scheme call to an unknown Procedure f:
>
> (f 3 x)
>
> the compiler should generate (the invokedynamic bytecode
> corresponding to):
>
> InvokeDynamic.apply(f, 3, x)
>
> The minimal generic CallSite support might be:
>
> static { Linkage.registerBootstrapMethod("kawa.lang.Dynamic",
> "linkDynamic");
>
> private static CallSite linkDynamic(Class caller, String name,
> MethodType type) {
> CallSite site = new CallSite(caller, name, type);
> MethodType genericHandleType = ...;
> MethodHandle genericHandle = MethodHandles.lookup()
> .findStatic(Dynamic.class, "genericApply", genericHandleType);
> site.setTarget(genericHandle);
> return site;
> }
>
> public static Object genericApply(Object function, Object... args) {
> if (function instanceof Procedure) {
> return ((Procedure) function).applyN(args);
> }
> else
> ... handle array indexing and other "pseudo-function" types ...;
> }
>
> So this seems like it should work and handle the generic case, but
> of course there is no performance win so far.
>
> So the first thing we need is to replace genericApply with one that is
> specialized on the actual function argument. I.e. instead of:
>
> return ((Procedure) function).applyN(args);
>
> we do:
>
> MethodHandle mh = ((Procedure) function).asMethodHandle();
> site.setTarget(mh);
>
> and so we end up doing:
>
> return mh.invoke(args);
>
> So we need to register the specialized method instead, and re-try that.
> Then we need to check future calls to see if the function has changed,
> and if so re-specialize. I haven't been able I haven't been able to find
> a tutorial/example for that - Google is not my friend this morning.
> Any cook-books out there for how to do this?
>
guardWithTest is the missing piece.
It should be something like that:
private static CallSite linkDynamic(Class caller, String name,
MethodType type) {
CallSite site = new CallSite(caller, name, type);
MethodHandle fallback = MethodHandles.insertArguments(#fallback,
0, site);
MethodHandle target = MethodHandles.collectArguments(fallback, type);
site.setTarget(target);
return site;
}
public static boolean refTest(Object procedure1, Object procedure2) {
return procedure1 == procedure2;
}
public static Object fallback(Callsite callsite, Object procedure,
Object[] args) {
MethodHandle mh = ((Procedure)procedure).asMethodHandle();
MethodHandle test = MethodHandles.insertArguments(#refTest, 1,
procedure);
MethodHandle invoker =
MethodHandles.genericInvoker(callsite.getTarget().type());
MethodHandle target = MethodHandles.insertArgument(invoker, 0, mh);
target = MethodHandles.guardWithTest(test, target, fallback);
callsite.setTarget(target);
return mh.invokeVarargs(args);
}
Perhaps you need to add some conversions with convertArguments.
But as I said, why do you want to use invokedynamic here ?
> After that I need to figure out how to do argument conversions. The Kawa
> compiler emits in each generic "apply" method necessary type conversions
> before it calls the actual specific method, and the CallSite handler has
> to duplicate that.
>
Rémi
More information about the mlvm-dev
mailing list