MethodHandles for Kawa and other functional languages?

Alessio Stalla alessiostalla at gmail.com
Thu Sep 30 00:44:39 PDT 2010


On Thu, Sep 30, 2010 at 3:08 AM, John Rose <john.r.rose at oracle.com> wrote:
> On Sep 29, 2010, at 5:00 PM, Per Bothner wrote:
>
>> Fundamentally, the question is: When the Scheme programmer passes
>> of function to a higher-level function (like map), what is the type
>> of the object passed: A MethodHandle?  A Procedure?  Something else?
>> There seem to be different kind of MethodHandles, so perhaps something
>> is appropriate.  Is there some blog article or cookbook discussing this?
>
> Quick answer to your next-to-last question:  The language-specific APIs should use their own interfaces or classes, so continue to use Procedure.  But if and when you go to JSR 292 API's you need to convert to the MH type.  The MethodHandleProvider (aka MethodHandleBox) interface is supposed to make this process more regular.
>
> For example, an invokedynamic bootstrap method (binding a Scheme call site) needs to return either a CallSite wrapped around a method handle (if it is to be rebindable) or a MethodHandle (if not).  In either case, you'll want to convert your Procedure down to a MH when binding it to an invokedynamic call site.
>
> Your internal field Procedure.mh field might be made lazy or even virtualized away, as long as MHP.asMethodHandle does something reasonable for every individual Procedure.  It depends on how or whether you want to use polymorphism in the Procedure type, or whether you want to do all the polymorphism through method handles.  At a minim u m, you'll want to make out-calls to random Java methods through method handles, instead of through reflection or thousands of inner classes.
>
> By the way, the usefulness (or not) of MHP is a matter of debate on the JSR 292 EG, so I'm eager for insights.
>
> Also, I will read your message over in more detail.

This is interesting, because I'm starting to evaluate JSR 292 in ABCL,
another JVM Lisp implementation (Common Lisp), and I'm pretty much
following John's advice already (I didn't know about MHP, so I
implemented my own Function.asMethodHandle).

Now ABCL compiles function calls - say (foo ...) - to something like

_theSymbolFoo.getSymbolFunctionOrDie().execute(...)

where _theSymbolFoo is a static field referring to the first-class
symbol object 'FOO and getSymbolFunctionOrDie() returns the function
associated with that symbol, or signals an error if the symbol has no
associated function. Functions are instances of ABCL's class Function.

My plan for bringing invokedynamic into that picture is to compile
function calls to (bytecode equivalent to):

InvokeDynamic.#"SOME-LISP-PACKAGE:FOO"(...)

and in the bootstrap method, roughly,

...
Symbol sym = readFromString(methodName);
MethodHandle mh = sym.getSymbolFunctionOrDie().asMethodHandle();
...

Then, to handle redefinition of functions, I'll store call sites into
a list for each symbol (say, callSites), and have

Symbol.setSymbolFunction(Function fun) {
  synchronized(callSites) {
    for(CallSite c : callSites) {
      c.setTarget(fun.asMethodHandle());
    }
    this.function = fun;
  }
}

Actually in my sketch implementation (yet to be integrated into the
compiler), callSites is a Set backed by a WeakHashMap. But I'm not
sure whether the weakness is actually required.

This way function lookup should be done only once, at linking time
(and at redefinition time), and all subsequent calls will be direct
method calls.

Regards,
Alessio Stalla


More information about the mlvm-dev mailing list