Be able to invoke a MethodHandle directly
John Rose
John.Rose at Sun.COM
Thu Oct 30 14:10:10 PDT 2008
On Oct 27, 2008, at 5:38 PM, Rémi Forax wrote:
>> In general, you use MHs.insertArgument to build bound method handles
>> to perform language-specific adaptation and dispatch. The attached
>> code (using the bound-in data to fill in free variables) needs to
>> perform the language-specific tests and conversions. Perhaps it also
>> attaches language specific control blocks, as implicit arguments.
>> Eventually the target method gets called, after all the tests and
>> argument adjustments. That invocation point is a direct MH.invoke
>> call.
>>
> Yes but this call isn't a real direct call, i.e it's a call
> done as a result of findVirtual(), unreflect(), etc.
> These calls are done by adapters not directly
I'll post some code to show what I mean... The essential idea is
that adapters can be user-defined. A user-defined adapter is created
by MHs.findMethod (aka findVirtual plus insertArgument) on an
instance of a user-defined class Foo, a subclass of Object. (Name of
the captured method is unimportant; could be 'invoke' by
convention.) The invoke method performs some user-defined logic
(probably data-driven from fields of Foo) and then selects the
ultimate target method. That target is called by invokevirtual
MH.invoke.
The weak point in this scheme is that you need one Foo.invoke
definition for each possible signature that your system might
process. We don't have a way yet to reify argument lists to create
user-defined code that is polymorphic over argument lists.
This is still better than the old state of affairs, where schemes
like this require a different method (and usually class) for each
name/signature pair. (Method handles abstract away from names, but
only partially from signatures.)
Also, the replication of customized code for each signature, in new
state of affairs, is improved by various built-in adapters which
perform low-level single-argument adaptation.
But doing a polymorphic inline cache (for example) will require user-
defined code; it's not a one-size-fits all problem that can be solved
in a JSR 292 library function.
Also, the Foo class above can have several entry points (overloadings
of invoke) to cut down on the number of signature-specific classes.
Flyby adapters, with reified argument lists, would provide the best
combination of polymorphic simplicity and performance. But even with
them, user-defined Foo adapters, for specific "favorite" signatures,
will probably be the most efficient mechanism.
> (btw you don't answer to my question about user-defined method handle
> with inconsistent method type).
You can't make a user-defined subclass of MethodHandle. The
constructor is effectively package-private. If you look at the EDR
code, you'll see that there is no way for random code to come in and
add a new subclass of MethodHandle.
>> Basically, if you want to build combinators, you need (a) bound
>> method handles and (b) direct MH.invoke calls. Step (a) creates the
>> wrapper that gets called, and step (b) calls the next guy in line.
>>
> I don't know if your remember my pathetic presentation ( :) ) but
> in the
> backport there is no line, all is flatten before being called and
> transformed
> to one bytecode blob to preserve "inlining budget" (charles, i love
> that
> expression).
That's like the DLR expression trees; it's a nice tactic, but I don't
think it scales (on the JVM) all the way out to arbitrary adaptation
algorithms (like PICs or multiple dispatch). For some (very simple)
adapters we might want to consider a reflection capability
(implementation private) which would allow a code generator to re-
generate an adapter chain. But for complex user-defined adapters, we
should just have an @Inline declaration (when appropriate) to adjust
the inlining budget.
>
>> This is a sort of tinkertoy set that can be used to build any needed
>> structure. BMH creation is one kind of connection point, and
>> MH.invoke is the complementary end.
>>
>>
>>> I don't think it's a good example since BGGA closures are
>>> covariant/contravariant,
>>> so the MethodHandle behind a closure can't be called directly
>>> because it
>>> need to be adapted.
>>>
>>
>> The adaptation is (in the EDR) a hardwired case, because (it is
>> likely) the JVM can optimize it easily. The adaptation could also be
>> expressed as a user-written BMH. Anything more complicated than a
>> Java implicit conversion *will* be expressed with a user-written BMH.
>>
> I don't believe in user-written BMH. A user have to deal with
> different
> method types (object vs primitive, number of arguments, etc)
> which is merly impossible if you don't box everything in an array as
> reflection do.
As mentioned above, we can do some replication of adapter code,
customized to various signatures. The user-define BMH will handle
one signature (actually a small range of signatures). It will avoid
the boxing overheads, which would be very costly.
> That why i have proposed a new method handle adapter to write
> combinator:
> see http://mail.openjdk.java.net/pipermail/mlvm-dev/2008-October/
> 000236.html
That's a nice one, but it doesn't have control structure in it, so it
can't do PIC or multiple dispatch (e.g., dynamic overload
resolution). User-defined adapters can do any and all of those things.
-- John
More information about the mlvm-dev
mailing list